From 041f2dfc65d6a216a32f4d2dcbe1ee0fb5c13926 Mon Sep 17 00:00:00 2001 From: Caitlin Ross Date: Thu, 10 Jun 2021 16:11:31 -0400 Subject: [PATCH 1/6] add plugin engine --- source/adios2/CMakeLists.txt | 2 + source/adios2/core/IO.cpp | 4 + source/adios2/engine/plugin/PluginEngine.cpp | 164 ++++++++++++++++++ source/adios2/engine/plugin/PluginEngine.h | 104 +++++++++++ source/adios2/engine/plugin/PluginEngine.inl | 44 +++++ .../engine/plugin/PluginEngineInterface.cpp | 29 ++++ .../engine/plugin/PluginEngineInterface.h | 48 +++++ 7 files changed, 395 insertions(+) create mode 100644 source/adios2/engine/plugin/PluginEngine.cpp create mode 100644 source/adios2/engine/plugin/PluginEngine.h create mode 100644 source/adios2/engine/plugin/PluginEngine.inl create mode 100644 source/adios2/engine/plugin/PluginEngineInterface.cpp create mode 100644 source/adios2/engine/plugin/PluginEngineInterface.h diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt index f71a997031..2ed246a96d 100644 --- a/source/adios2/CMakeLists.txt +++ b/source/adios2/CMakeLists.txt @@ -56,6 +56,8 @@ add_library(adios2_core engine/null/NullEngine.cpp engine/nullcore/NullCoreWriter.cpp engine/nullcore/NullCoreWriter.tcc + + engine/plugin/PluginEngine.cpp engine/plugin/PluginEngineInterface.cpp #toolkit toolkit/format/buffer/Buffer.cpp toolkit/format/buffer/BufferV.cpp diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp index feb777c516..e94b891ffd 100644 --- a/source/adios2/core/IO.cpp +++ b/source/adios2/core/IO.cpp @@ -32,6 +32,7 @@ #include "adios2/engine/mhs/MhsWriter.h" #include "adios2/engine/null/NullEngine.h" #include "adios2/engine/nullcore/NullCoreWriter.h" +#include "adios2/engine/plugin/PluginEngine.h" #include "adios2/engine/skeleton/SkeletonReader.h" #include "adios2/engine/skeleton/SkeletonWriter.h" @@ -129,6 +130,9 @@ std::unordered_map Factory = { {"nullcore", {IO::NoEngine("ERROR: nullcore engine does not support read mode"), IO::MakeEngine}}, + {"plugin", + {IO::MakeEngine, + IO::MakeEngine}}, }; // Synchronize access to the factory in case one thread is diff --git a/source/adios2/engine/plugin/PluginEngine.cpp b/source/adios2/engine/plugin/PluginEngine.cpp new file mode 100644 index 0000000000..fe72c9ebd6 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngine.cpp @@ -0,0 +1,164 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngine.cpp + * + * Created on: July 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#include "PluginEngine.h" +#include "PluginEngineInterface.h" + +#include +#include +#include +#include +#include + +#include "adios2/helper/adiosDynamicBinder.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +/******************************************************************************/ + +struct PluginEngine::Impl +{ + using Registry = + std::map>; + static Registry m_Registry; + + std::string m_PluginName; + std::unique_ptr m_Binder; + EngineCreateFun m_HandleCreate; + EngineDestroyFun m_HandleDestroy; + PluginEngineInterface *m_Plugin = nullptr; +}; +PluginEngine::Impl::Registry PluginEngine::Impl::m_Registry; + +/******************************************************************************/ + +void PluginEngine::RegisterPlugin(const std::string pluginName, + EngineCreateFun create, + EngineDestroyFun destroy) +{ + PluginEngine::Impl::m_Registry.emplace(pluginName, + std::make_pair(create, destroy)); +} + +/******************************************************************************/ + +PluginEngine::PluginEngine(IO &io, const std::string &name, const Mode mode, + helper::Comm comm) +: Engine("Plugin", io, name, mode, comm.Duplicate()), m_Impl(new Impl) +{ + Init(); + m_Impl->m_Plugin = m_Impl->m_HandleCreate(io, m_Impl->m_PluginName, mode, + comm.Duplicate()); +} + +PluginEngine::~PluginEngine() { m_Impl->m_HandleDestroy(m_Impl->m_Plugin); } + +StepStatus PluginEngine::BeginStep(StepMode mode, const float timeoutSeconds) +{ + return m_Impl->m_Plugin->BeginStep(mode, timeoutSeconds); +} + +void PluginEngine::PerformPuts() { m_Impl->m_Plugin->PerformPuts(); } + +void PluginEngine::PerformGets() { m_Impl->m_Plugin->PerformGets(); } + +void PluginEngine::EndStep() { m_Impl->m_Plugin->EndStep(); } + +void PluginEngine::Init() +{ + auto paramPluginNameIt = m_IO.m_Parameters.find("PluginName"); + if (paramPluginNameIt == m_IO.m_Parameters.end()) + { + throw std::invalid_argument("PluginEngine: PluginName must be " + "specified in engine parameters"); + } + m_Impl->m_PluginName = paramPluginNameIt->second; + + // First we check to see if we can find the plugin currently registerd + auto registryEntryIt = + PluginEngine::Impl::m_Registry.find(m_Impl->m_PluginName); + + if (registryEntryIt != PluginEngine::Impl::m_Registry.end()) + { + m_Impl->m_HandleCreate = registryEntryIt->second.first; + m_Impl->m_HandleDestroy = registryEntryIt->second.second; + } + else + { + // It's not currently registered so try to load it from a shared + // library + // + auto paramPluginLibraryIt = m_IO.m_Parameters.find("PluginLibrary"); + if (paramPluginLibraryIt == m_IO.m_Parameters.end()) + { + throw std::invalid_argument( + "PluginEngine: PluginLibrary must be specified in " + "engine parameters if no PluginName " + "is specified"); + } + std::string &pluginLibrary = paramPluginLibraryIt->second; + + m_Impl->m_Binder.reset(new helper::DynamicBinder(pluginLibrary)); + + m_Impl->m_HandleCreate = reinterpret_cast( + m_Impl->m_Binder->GetSymbol("EngineCreate")); + if (!m_Impl->m_HandleCreate) + { + throw std::runtime_error("PluginEngine: Unable to locate " + "EngineCreate symbol in specified plugin " + "library"); + } + + m_Impl->m_HandleDestroy = reinterpret_cast( + m_Impl->m_Binder->GetSymbol("EngineDestroy")); + if (!m_Impl->m_HandleDestroy) + { + throw std::runtime_error("PluginEngine: Unable to locate " + "EngineDestroy symbol in specified plugin " + "library"); + } + } +} + +#define declare(T) \ + void PluginEngine::DoPutSync(Variable &variable, const T *values) \ + { \ + m_Impl->m_Plugin->DoPutSync(variable, values); \ + } \ + void PluginEngine::DoPutDeferred(Variable &variable, const T *values) \ + { \ + m_Impl->m_Plugin->DoPutDeferred(variable, values); \ + } \ + void PluginEngine::DoGetSync(Variable &variable, T *values) \ + { \ + m_Impl->m_Plugin->DoGetSync(variable, values); \ + } \ + void PluginEngine::DoGetDeferred(Variable &variable, T *values) \ + { \ + m_Impl->m_Plugin->DoGetDeferred(variable, values); \ + } + +ADIOS2_FOREACH_STDTYPE_1ARG(declare) +#undef declare + +void PluginEngine::DoClose(const int transportIndex) +{ + m_Impl->m_Plugin->Close(transportIndex); +} + +} // end namespace engine +} // end namespace core +} // end namespace adios2 diff --git a/source/adios2/engine/plugin/PluginEngine.h b/source/adios2/engine/plugin/PluginEngine.h new file mode 100644 index 0000000000..3e8c5a8172 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngine.h @@ -0,0 +1,104 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngine.h Support for an engine implemented outside libadios2 + * + * Created on: July 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ +#define ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ + +#include "PluginEngineInterface.h" + +#include // for function +#include // for unique_ptr +#include // for string +#include // for add_pointer +#include // for vector + +#include "adios2/common/ADIOSMacros.h" +#include "adios2/common/ADIOSTypes.h" +#include "adios2/core/Engine.h" +#include "adios2/core/IO.h" +#include "adios2/core/Variable.h" +#include "adios2/core/VariableCompound.h" +#include "adios2/helper/adiosComm.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +/** A front-end wrapper for an engine implemented outside of libadios2 */ +class PluginEngine : public Engine +{ +public: + // Function pointers used for the plugin factory methods + using EngineCreatePtr = std::add_pointer::type; + using EngineDestroyPtr = + std::add_pointer::type; + using EngineCreateFun = + std::function::type>; + using EngineDestroyFun = + std::function::type>; + + static void RegisterPlugin(const std::string pluginName, + EngineCreateFun create, + EngineDestroyFun destroy); + static void RegisterPlugin(const std::string pluginName, + EngineCreatePtr create, EngineDestroyPtr destroy) + { + RegisterPlugin(pluginName, EngineCreateFun(create), + EngineDestroyFun(destroy)); + } + + // This is just a shortcut method to handle the case where the class type is + // directly available to the caller so a simple new and delete call is + // sufficient to create and destroy the engine object + template + static void RegisterPlugin(const std::string name); + +public: + PluginEngine(IO &io, const std::string &name, const Mode mode, + helper::Comm comm); + virtual ~PluginEngine(); + + StepStatus BeginStep(StepMode mode, + const float timeoutSeconds = 0.f) override; + void PerformPuts() override; + void PerformGets() override; + void EndStep() override; + +protected: + void Init() override; + +#define declare(T) \ + void DoPutSync(Variable &, const T *) override; \ + void DoPutDeferred(Variable &, const T *) override; \ + void DoGetSync(Variable &, T *) override; \ + void DoGetDeferred(Variable &, T *) override; + + ADIOS2_FOREACH_STDTYPE_1ARG(declare) +#undef declare + + void DoClose(const int transportIndex = -1) override; + +private: + struct Impl; + std::unique_ptr m_Impl; +}; + +} // end namespace engine +} // end namespace core +} // end namespace adios2 + +#include "PluginEngine.inl" + +#endif /* ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ */ diff --git a/source/adios2/engine/plugin/PluginEngine.inl b/source/adios2/engine/plugin/PluginEngine.inl new file mode 100644 index 0000000000..3006e45c53 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngine.inl @@ -0,0 +1,44 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngine.h Support for an engine implemented outside libadios2 + * + * Created on: July 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#ifndef ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ +#define ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ +#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ +#error "Inline file should only be included from it's header, never on it's own" +#endif + +#include "PluginEngine.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +template +void PluginEngine::RegisterPlugin(const std::string name) +{ + EngineCreateFun createFun = + [](IO &io, const std::string &name, const Mode openMode, + helper::Comm comm) -> PluginEngineInterface * { + return new T(io, name, openMode, comm.Duplicate()); + }; + EngineDestroyFun destroyFun = [](Engine *obj) -> void { delete obj; }; + + RegisterPlugin(name, createFun, destroyFun); +} + +} // end namespace engine +} // end namespace core +} // end namespace adios2 + +#endif // ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ diff --git a/source/adios2/engine/plugin/PluginEngineInterface.cpp b/source/adios2/engine/plugin/PluginEngineInterface.cpp new file mode 100644 index 0000000000..18b84b7586 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngineInterface.cpp @@ -0,0 +1,29 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngineInterface.cxx + * + * Created on: July 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#include "PluginEngineInterface.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +PluginEngineInterface::PluginEngineInterface(IO &io, const std::string &name, + const Mode mode, helper::Comm comm) +: Engine("PluginInterface", io, name, mode, std::move(comm)) +{ +} + +} // end namespace engine +} // end namespace core +} // end namespace adios2 diff --git a/source/adios2/engine/plugin/PluginEngineInterface.h b/source/adios2/engine/plugin/PluginEngineInterface.h new file mode 100644 index 0000000000..9a8054d304 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngineInterface.h @@ -0,0 +1,48 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngineInterface.h Engines using the plugin interface should derive from + * this class. + * + * Created on: July 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINEINTERFACE_H_ +#define ADIOS2_ENGINE_PLUGIN_PLUGINENGINEINTERFACE_H_ + +/// \cond EXCLUDE_FROM_DOXYGEN +/// \endcond + +#include "adios2/common/ADIOSConfig.h" +#include "adios2/common/ADIOSTypes.h" +#include "adios2/core/Engine.h" +#include "adios2/core/IO.h" +#include "adios2/helper/adiosComm.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +/** An engine interface to be used by the plugin infrastructure */ +class PluginEngineInterface : public Engine +{ + // Give the plugin engine access to everything + friend class PluginEngine; + +public: + PluginEngineInterface(IO &io, const std::string &name, const Mode mode, + helper::Comm comm); + virtual ~PluginEngineInterface() = default; +}; + +} // end namespace engine +} // end namespace core +} // end namespace adios2 + +#endif /* ADIOS2_ENGINE_PLUGIN_PLUGINENGINEINTERFACE_H_ */ From e9835a38f7ec0648abfec801ed43a9973aa9265a Mon Sep 17 00:00:00 2001 From: Caitlin Ross Date: Thu, 10 Jun 2021 16:29:48 -0400 Subject: [PATCH 2/6] plugin engine: read/write example --- examples/CMakeLists.txt | 1 + examples/plugins/CMakeLists.txt | 6 + examples/plugins/engine/CMakeLists.txt | 16 ++ examples/plugins/engine/ExampleReadPlugin.cpp | 135 ++++++++++ examples/plugins/engine/ExampleReadPlugin.h | 83 ++++++ examples/plugins/engine/ExampleReadPlugin.tcc | 236 ++++++++++++++++++ .../plugins/engine/ExampleWritePlugin.cpp | 115 +++++++++ examples/plugins/engine/ExampleWritePlugin.h | 84 +++++++ .../plugins/engine/ExampleWritePlugin.tcc | 56 +++++ .../engine/examplePluginEngine_read.cpp | 125 ++++++++++ .../engine/examplePluginEngine_write.cpp | 105 ++++++++ 11 files changed, 962 insertions(+) create mode 100644 examples/plugins/CMakeLists.txt create mode 100644 examples/plugins/engine/CMakeLists.txt create mode 100644 examples/plugins/engine/ExampleReadPlugin.cpp create mode 100644 examples/plugins/engine/ExampleReadPlugin.h create mode 100644 examples/plugins/engine/ExampleReadPlugin.tcc create mode 100644 examples/plugins/engine/ExampleWritePlugin.cpp create mode 100644 examples/plugins/engine/ExampleWritePlugin.h create mode 100644 examples/plugins/engine/ExampleWritePlugin.tcc create mode 100644 examples/plugins/engine/examplePluginEngine_read.cpp create mode 100644 examples/plugins/engine/examplePluginEngine_write.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 227d6ae2e7..8c77c44021 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(hello) add_subdirectory(query) add_subdirectory(useCases) add_subdirectory(inlineMWE) +add_subdirectory(plugins) if(ADIOS2_HAVE_MPI) add_subdirectory(heatTransfer) diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt new file mode 100644 index 0000000000..3f65197ad1 --- /dev/null +++ b/examples/plugins/CMakeLists.txt @@ -0,0 +1,6 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +add_subdirectory(engine) diff --git a/examples/plugins/engine/CMakeLists.txt b/examples/plugins/engine/CMakeLists.txt new file mode 100644 index 0000000000..a4f3e812c2 --- /dev/null +++ b/examples/plugins/engine/CMakeLists.txt @@ -0,0 +1,16 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +add_executable(examplePluginEngine_write + examplePluginEngine_write.cpp + ExampleWritePlugin.h ExampleWritePlugin.cpp +) +target_link_libraries(examplePluginEngine_write adios2::cxx11 adios2_core) + +add_executable(examplePluginEngine_read + examplePluginEngine_read.cpp + ExampleReadPlugin.h ExampleReadPlugin.cpp +) +target_link_libraries(examplePluginEngine_read adios2::cxx11 adios2_core) diff --git a/examples/plugins/engine/ExampleReadPlugin.cpp b/examples/plugins/engine/ExampleReadPlugin.cpp new file mode 100644 index 0000000000..cb29f28a29 --- /dev/null +++ b/examples/plugins/engine/ExampleReadPlugin.cpp @@ -0,0 +1,135 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleReadPlugin.cpp + * + * Created on: Jul 5, 2021 + * Author: Caitlin Ross + */ + +#include "ExampleReadPlugin.h" +#include "ExampleReadPlugin.tcc" + +#include "adios2/helper/adiosType.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +ExampleReadPlugin::ExampleReadPlugin(IO &io, const std::string &name, + const Mode mode, helper::Comm comm) +: PluginEngineInterface(io, name, mode, comm.Duplicate()) +{ + Init(); +} + +ExampleReadPlugin::~ExampleReadPlugin() +{ + m_DataFile.close(); + m_VarFile.close(); +} + +Dims convertStrToDims(const std::string &str) +{ + Dims dims; + if (str.size() > 2) + { + auto vals = str.substr(1, str.size() - 2); + std::stringstream ss(vals); + while (ss.good()) + { + std::string substr; + std::getline(ss, substr, ','); + dims.push_back(std::stoi(substr)); + } + } + return dims; +} + +void ExampleReadPlugin::Init() +{ + std::string dir = "ExamplePlugin"; + auto paramFileNameIt = m_IO.m_Parameters.find("DirName"); + if (paramFileNameIt != m_IO.m_Parameters.end()) + { + dir = paramFileNameIt->second; + } + + std::string fileName = dir + "/data.txt"; + m_DataFile.open(fileName, std::ofstream::in); + if (!m_DataFile) + { + throw std::ios_base::failure("ExampleReadPlugin: Failed to open file " + + fileName); + } + + std::string varfName = dir + "/vars.txt"; + m_VarFile.open(varfName, std::ofstream::in); + if (!m_VarFile) + { + throw std::ios_base::failure("ExampleReadPlugin: Failed to open file " + + varfName + ".vars"); + } + + // get var info + while (m_VarFile.good()) + { + std::string name, typeStr, shapeStr, startStr, countStr; + std::getline(m_VarFile, name, ';'); + std::getline(m_VarFile, typeStr, ';'); + std::getline(m_VarFile, shapeStr, ';'); + std::getline(m_VarFile, startStr, ';'); + std::getline(m_VarFile, countStr); + + auto shape = convertStrToDims(shapeStr); + auto start = convertStrToDims(startStr); + auto count = convertStrToDims(countStr); + + const DataType type = helper::GetDataTypeFromString(typeStr); + if (type == DataType::Compound) + { + // not supported + } +#define declare_template_instantiation(T) \ + else if (type == helper::GetDataType()) \ + { \ + AddVariable(name, shape, start, count); \ + } + ADIOS2_FOREACH_STDTYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + } +} + +#define declare(T) \ + void ExampleReadPlugin::DoGetSync(Variable &variable, T *values) \ + { \ + ReadVariable(variable, values); \ + } \ + void ExampleReadPlugin::DoGetDeferred(Variable &variable, T *values) \ + { \ + ReadVariable(variable, values); \ + } +ADIOS2_FOREACH_STDTYPE_1ARG(declare) +#undef declare + +StepStatus ExampleReadPlugin::BeginStep(StepMode mode, + const float timeoutSeconds) +{ + return StepStatus::OK; +} + +void ExampleReadPlugin::PerformGets() {} + +size_t ExampleReadPlugin::CurrentStep() const { return m_CurrentStep; } + +void ExampleReadPlugin::EndStep() { m_CurrentStep++; } + +void ExampleReadPlugin::DoClose(const int transportIndex) {} + +} // end namespace engine +} // end namespace core +} // end namespace adios2 diff --git a/examples/plugins/engine/ExampleReadPlugin.h b/examples/plugins/engine/ExampleReadPlugin.h new file mode 100644 index 0000000000..b40efa6ce0 --- /dev/null +++ b/examples/plugins/engine/ExampleReadPlugin.h @@ -0,0 +1,83 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleReadPlugin.h Simple file reading engine for reading files written by + * the ExampleWritePlugin engine. Looks for directory + * (called "ExamplePlugin" by default, but can be changed with engine parameter + * "DirName") and reads variable info from vars.txt and actual data from + * data.txt. + * + * Created on: Jul 5, 2021 + * Author: Caitlin Ross + */ + +#ifndef EXAMPLEREADPLUGIN_H_ +#define EXAMPLEREADPLUGIN_H_ + +#include +#include + +#include "adios2/common/ADIOSMacros.h" +#include "adios2/common/ADIOSTypes.h" +#include "adios2/core/IO.h" +#include "adios2/engine/plugin/PluginEngineInterface.h" +#include "adios2/helper/adiosComm.h" +#include "adios2/helper/adiosString.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +/** An engine interface to be used by the plugin infrastructure */ +class ExampleReadPlugin : public PluginEngineInterface +{ +public: + ExampleReadPlugin(IO &io, const std::string &name, const Mode openMode, + helper::Comm comm); + virtual ~ExampleReadPlugin(); + + /** Indicates beginning of a step **/ + StepStatus BeginStep(StepMode mode = StepMode::Read, + const float timeoutSeconds = -1.0) override; + + /** Indicates end of a step **/ + void EndStep() override; + + /** Return the current step **/ + size_t CurrentStep() const override; + + /** Execute deferred mode Gets **/ + void PerformGets() override; + +protected: + void Init() override; + +#define declare(T) \ + void DoGetSync(Variable &variable, T *values) override; \ + void DoGetDeferred(Variable &variable, T *values) override; + ADIOS2_FOREACH_STDTYPE_1ARG(declare) +#undef declare + + void DoClose(const int transportIndex = -1) override; + +private: + std::ifstream m_DataFile; + std::ifstream m_VarFile; + size_t m_CurrentStep = 0; + + template + void AddVariable(const std::string &name, Dims shape, Dims start, + Dims count); + + template + void ReadVariable(Variable &variable, T *values); +}; + +} // end namespace engine +} // end namespace core +} // end namespace adios2 +#endif /* EXAMPLEREADPLUGIN_H_ */ diff --git a/examples/plugins/engine/ExampleReadPlugin.tcc b/examples/plugins/engine/ExampleReadPlugin.tcc new file mode 100644 index 0000000000..3a103a29b5 --- /dev/null +++ b/examples/plugins/engine/ExampleReadPlugin.tcc @@ -0,0 +1,236 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleReadPlugin.tcc + * + * Created on: Jul 5, 2021 + * Author: Caitlin Ross + */ + +#ifndef EXAMPLEREADPLUGIN_TCC_ +#define EXAMPLEREADPLUGIN_TCC_ + +#include "ExampleReadPlugin.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +template +void ExampleReadPlugin::AddVariable(const std::string &name, Dims shape, + Dims start, Dims count) +{ + core::Variable *v = m_IO.InquireVariable(name); + if (!v) + { + m_IO.DefineVariable(name, shape, start, count); + } +} + +template +inline void ExampleReadPlugin::ReadVariable(Variable &variable, T *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + auto delimPos = line.find(","); + auto name = line.substr(0, delimPos); + size_t step = std::stoul(line.substr(delimPos + 1)); + if (name == variable.m_Name && m_CurrentStep == step) + { + std::string vals; + std::getline(m_DataFile, vals); + if (vals.find(",") == vals.npos) + { + values[0] = helper::StringTo(vals, ""); + } + else + { + std::istringstream ss(vals); + std::string val; + int i = 0; + while (std::getline(ss, val, ',')) + { + values[i] = helper::StringTo(val, ""); + i++; + } + } + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + std::string *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + std::getline(m_DataFile, values[0]); + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + char *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + m_DataFile.get(&values[i], 1, ','); + } + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + unsigned char *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + char val; + m_DataFile.get(&val, 1, ','); + values[i] = static_cast(val); + } + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + signed char *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + char val; + m_DataFile.get(&val, 1, ','); + values[i] = static_cast(val); + } + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + short *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + std::string val; + std::getline(m_DataFile, val, ','); + values[i] = static_cast(std::stoi(val)); + } + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + unsigned short *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + std::string val; + std::getline(m_DataFile, val, ','); + values[i] = static_cast(std::stoi(val)); + } + break; + } + } +} + +template <> +inline void ExampleReadPlugin::ReadVariable(Variable &variable, + long double *values) +{ + while (m_DataFile.good()) + { + std::string line; + std::getline(m_DataFile, line); + if (line == variable.m_Name) + { + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + std::string val; + std::getline(m_DataFile, val, ','); + try + { + values[i] = std::strtold(val.c_str(), nullptr); + } + catch (...) + { + std::throw_with_nested(std::invalid_argument( + "ERROR: could not cast " + val + " to long double ")); + } + } + break; + } + } +} + +template <> +inline void +ExampleReadPlugin::ReadVariable(Variable> &variable, + std::complex *values) +{ + throw std::invalid_argument( + "ERROR: std::complex not supported in this engine"); +} + +template <> +inline void +ExampleReadPlugin::ReadVariable(Variable> &variable, + std::complex *values) +{ + throw std::invalid_argument( + "ERROR: std::complex not supported in this engine"); +} +} +} +} +#endif /* EXAMPLEREADPLUGIN_TCC_ */ diff --git a/examples/plugins/engine/ExampleWritePlugin.cpp b/examples/plugins/engine/ExampleWritePlugin.cpp new file mode 100644 index 0000000000..48649827b6 --- /dev/null +++ b/examples/plugins/engine/ExampleWritePlugin.cpp @@ -0,0 +1,115 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleWritePlugin.cpp + * + * Created on: Jul 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#include "ExampleWritePlugin.h" +#include "ExampleWritePlugin.tcc" + +#include "adios2/helper/adiosSystem.h" + +namespace adios2 +{ +namespace core +{ + +namespace engine +{ + +ExampleWritePlugin::ExampleWritePlugin(IO &io, const std::string &name, + const Mode mode, helper::Comm comm) +: PluginEngineInterface(io, name, mode, comm.Duplicate()) +{ + Init(); +} + +ExampleWritePlugin::~ExampleWritePlugin() +{ + m_DataFile.close(); + m_VarFile.close(); +} + +void ExampleWritePlugin::Init() +{ + std::string dir = "ExamplePlugin"; + auto paramFileNameIt = m_IO.m_Parameters.find("DirName"); + if (paramFileNameIt != m_IO.m_Parameters.end()) + { + dir = paramFileNameIt->second; + } + helper::CreateDirectory(dir); + + std::string fileName = dir + "/data.txt"; + m_DataFile.open(fileName); + if (!m_DataFile) + { + throw std::ios_base::failure( + "ExampleWritePlugin: Failed to open file " + fileName); + } + + std::string varfName = dir + "/vars.txt"; + m_VarFile.open(varfName); + if (!m_VarFile) + { + throw std::ios_base::failure( + "ExampleWritePlugin: Failed to open file " + varfName); + } +} + +StepStatus ExampleWritePlugin::BeginStep(StepMode mode, + const float timeoutSeconds) +{ + WriteVarsFromIO(); + return StepStatus::OK; +} + +size_t ExampleWritePlugin::CurrentStep() const { return m_CurrentStep; } + +void ExampleWritePlugin::EndStep() { m_CurrentStep++; } + +#define declare(T) \ + void ExampleWritePlugin::DoPutSync(Variable &variable, const T *values) \ + { \ + WriteArray(variable, values); \ + } \ + void ExampleWritePlugin::DoPutDeferred(Variable &variable, \ + const T *values) \ + { \ + WriteArray(variable, values); \ + } +ADIOS2_FOREACH_STDTYPE_1ARG(declare) +#undef declare + +void ExampleWritePlugin::PerformPuts() { WriteVarsFromIO(); } + +void ExampleWritePlugin::DoClose(const int transportIndex) {} + +void ExampleWritePlugin::WriteVarsFromIO() +{ + const core::VarMap &variables = m_IO.GetVariables(); + for (const auto &vpair : variables) + { + const std::string &varName = vpair.first; + const DataType varType = vpair.second->m_Type; +#define declare_template_instantiation(T) \ + if (varType == helper::GetDataType()) \ + { \ + core::Variable *v = m_IO.InquireVariable(varName); \ + if (!v) \ + return; \ + WriteVariableInfo(*v); \ + } + ADIOS2_FOREACH_STDTYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + } +} + +} // end namespace engine +} // end namespace core +} // end namespace adios2 diff --git a/examples/plugins/engine/ExampleWritePlugin.h b/examples/plugins/engine/ExampleWritePlugin.h new file mode 100644 index 0000000000..732130deaa --- /dev/null +++ b/examples/plugins/engine/ExampleWritePlugin.h @@ -0,0 +1,84 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleWritePlugin.h Simple file writing engine. Creates directory + * (called "ExamplePlugin" by default, but can be changed with engine parameter + * "DirName") and writes variable info to vars.txt and actual data to data.txt. + * + * Created on: Jul 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#ifndef EXAMPLEWRITEPLUGIN_H_ +#define EXAMPLEWRITEPLUGIN_H_ + +#include +#include +#include + +#include "adios2/common/ADIOSMacros.h" +#include "adios2/common/ADIOSTypes.h" +#include "adios2/core/IO.h" +#include "adios2/engine/plugin/PluginEngineInterface.h" +#include "adios2/helper/adiosComm.h" +#include "adios2/helper/adiosType.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +/** An engine interface to be used by the plugin infrastructure */ +class ExampleWritePlugin : public PluginEngineInterface +{ +public: + ExampleWritePlugin(IO &io, const std::string &name, const Mode openMode, + helper::Comm comm); + virtual ~ExampleWritePlugin(); + + /** Indicates beginning of a step **/ + StepStatus BeginStep(StepMode mode, + const float timeoutSeconds = -1.0) override; + + /** Indicates end of a step **/ + void EndStep() override; + + /** Return the current step **/ + size_t CurrentStep() const override; + + /** Execute deferred mode Puts **/ + void PerformPuts() override; + +protected: + void Init() override; + +#define declare(T) \ + void DoPutSync(Variable &variable, const T *values) override; \ + void DoPutDeferred(Variable &variable, const T *values) override; + ADIOS2_FOREACH_STDTYPE_1ARG(declare) +#undef declare + + void DoClose(const int transportIndex = -1) override; + +private: + std::ofstream m_DataFile; + std::ofstream m_VarFile; + size_t m_CurrentStep = 0; + + void WriteVarsFromIO(); + + template + void WriteVariableInfo(core::Variable &variable); + + template + void WriteArray(Variable &variable, const T *values); +}; + +} // end namespace engine +} // end namespace core +} // end namespace adios2 +#endif /* EXAMPLEWRITEPLUGIN_H_ */ diff --git a/examples/plugins/engine/ExampleWritePlugin.tcc b/examples/plugins/engine/ExampleWritePlugin.tcc new file mode 100644 index 0000000000..3848631a33 --- /dev/null +++ b/examples/plugins/engine/ExampleWritePlugin.tcc @@ -0,0 +1,56 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleWritePlugin.tcc + * + * Created on: Jul 5, 2021 + * Author: Chuck Atkins + * Caitlin Ross + */ + +#ifndef EXAMPLEWRITEPLUGIN_TCC_ +#define EXAMPLEWRITEPLUGIN_TCC_ + +#include "ExampleWritePlugin.h" + +namespace adios2 +{ +namespace core +{ +namespace engine +{ + +template +void ExampleWritePlugin::WriteVariableInfo(core::Variable &variable) +{ + /** write basic variable info to file **/ + m_VarFile << variable.m_Name << ";" << variable.m_Type << ";" + << variable.m_Shape << ";" << variable.m_Start << ";" + << variable.m_Count << std::endl; +} + +template +void ExampleWritePlugin::WriteArray(Variable &variable, const T *values) +{ + /** Write variable name and step to file, followed by the actual data on the + * next line **/ + m_DataFile << variable.m_Name << "," << m_CurrentStep << std::endl; + for (size_t i = 0; i < variable.SelectionSize(); ++i) + { + m_DataFile << values[i]; + if (i < variable.SelectionSize() - 1) + { + m_DataFile << ","; + } + else + { + m_DataFile << std::endl; + } + } +} + +} // end namespace engine +} // end namespace core +} // end namespace adios2 +#endif /* EXAMPLEWRITEPLUGIN_TCC_ */ diff --git a/examples/plugins/engine/examplePluginEngine_read.cpp b/examples/plugins/engine/examplePluginEngine_read.cpp new file mode 100644 index 0000000000..d9c6b95317 --- /dev/null +++ b/examples/plugins/engine/examplePluginEngine_read.cpp @@ -0,0 +1,125 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * examplePluginEngine_read.cpp example showing how to use ExampleReadPlugin + * engine + * + * Created on: July 5, 2021 + * Author: Caitlin Ross + */ + +#include //std::ios_base::failure +#include //std::cout +#include //std::invalid_argument std::exception +#include + +#include "adios2.h" +#include "adios2/engine/plugin/PluginEngine.h" + +#include "ExampleReadPlugin.h" + +void testStreaming(adios2::Engine &reader, std::vector &myFloats, + adios2::Variable &var) +{ + for (int i = 0; i < 2; i++) + { + if (i == 1) + { + for (auto &num : myFloats) + { + num *= 2; + } + } + + reader.BeginStep(); + std::vector readFloats; + reader.Get(var, readFloats); + reader.EndStep(); + + if (readFloats == myFloats) + { + std::cout << "data was read correctly!" << std::endl; + } + else + { + std::cout << "data was not read correctly!" << std::endl; + } + } +} + +int main(int argc, char *argv[]) +{ + bool streaming = false; + if (argc > 1) + { + streaming = std::atoi(argv[1]) == 1; + } + + std::vector myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + /** Register Plugin with the PluginEngine **/ + adios2::core::engine::PluginEngine::RegisterPlugin< + adios2::core::engine::ExampleReadPlugin>("MyPlugin"); + + try + { + /** ADIOS class factory of IO class objects */ + adios2::ADIOS adios; + + /*** IO class object: settings and factory of Settings: Variables, + * Parameters, Transports, and Execution: Engines */ + adios2::IO io = adios.DeclareIO("PluginIO"); + + /** Engine derived class, spawned to start IO operations */ + io.SetEngine("Plugin"); + io.SetParameters({{"PluginName", "MyPlugin"}}); + adios2::Engine reader = io.Open("TestPlugin", adios2::Mode::Read); + + auto var = io.InquireVariable("data"); + if (!var) + { + std::cout << "variable does not exist" << std::endl; + } + + if (streaming) + { + testStreaming(reader, myFloats, var); + } + else + { + std::vector readFloats; + reader.Get(var, readFloats); + reader.PerformGets(); + + if (readFloats == myFloats) + { + std::cout << "data was read correctly!" << std::endl; + } + else + { + std::cout << "data was not read correctly!" << std::endl; + } + } + + /** Engine becomes unreachable after this*/ + reader.Close(); + } + catch (std::invalid_argument &e) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::ios_base::failure &e) + { + std::cout << "IO System base failure exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::exception &e) + { + std::cout << "Exception, STOPPING PROGRAM from rank\n"; + std::cout << e.what() << "\n"; + } + + return 0; +} diff --git a/examples/plugins/engine/examplePluginEngine_write.cpp b/examples/plugins/engine/examplePluginEngine_write.cpp new file mode 100644 index 0000000000..5c87f4a7e1 --- /dev/null +++ b/examples/plugins/engine/examplePluginEngine_write.cpp @@ -0,0 +1,105 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * examplePluginEngine_write.cpp example showing how to use ExampleWritePlugin + * engine + * + * Created on: July 5, 2021 + * Author: Caitlin Ross + */ + +#include //std::ios_base::failure +#include //std::cout +#include //std::invalid_argument std::exception +#include + +#include "adios2.h" +#include "adios2/engine/plugin/PluginEngine.h" + +#include "ExampleWritePlugin.h" + +void testStreaming(adios2::Engine &writer, std::vector &myFloats, + adios2::Variable &var) +{ + for (int i = 0; i < 2; i++) + { + if (i == 1) + { + for (auto &num : myFloats) + { + num *= 2; + } + } + writer.BeginStep(); + writer.Put(var, myFloats.data()); + writer.EndStep(); + } +} + +int main(int argc, char *argv[]) +{ + bool streaming = false; + if (argc > 1) + { + streaming = std::atoi(argv[1]) == 1; + } + + /** Application variable */ + std::vector myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const std::size_t Nx = myFloats.size(); + + /** Register Plugin with the PluginEngine **/ + adios2::core::engine::PluginEngine::RegisterPlugin< + adios2::core::engine::ExampleWritePlugin>("MyPlugin"); + + try + { + /** ADIOS class factory of IO class objects */ + adios2::ADIOS adios; + + /*** IO class object: settings and factory of Settings: Variables, + * Parameters, Transports, and Execution: Engines */ + adios2::IO io = adios.DeclareIO("PluginIO"); + + /** global array: name, { shape (total dimensions) }, { start (local) }, + * { count (local) }, all are constant dimensions */ + adios2::Variable var = io.DefineVariable( + "data", {}, {}, {Nx}, adios2::ConstantDims); + + /** Engine derived class, spawned to start IO operations */ + io.SetEngine("Plugin"); + io.SetParameters({{"PluginName", "MyPlugin"}}); + adios2::Engine writer = io.Open("TestPlugin", adios2::Mode::Write); + + if (streaming) + { + testStreaming(writer, myFloats, var); + } + else + { + writer.Put(var, myFloats.data()); + writer.PerformPuts(); + } + + /** Engine becomes unreachable after this*/ + writer.Close(); + } + catch (std::invalid_argument &e) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::ios_base::failure &e) + { + std::cout << "IO System base failure exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::exception &e) + { + std::cout << "Exception, STOPPING PROGRAM from rank\n"; + std::cout << e.what() << "\n"; + } + + return 0; +} From c65ff89832bbd0c1e123191f9ee4a1c076704156 Mon Sep 17 00:00:00 2001 From: Caitlin Ross Date: Mon, 19 Jul 2021 14:44:20 -0400 Subject: [PATCH 3/6] install core headers for plugin engine --- source/adios2/CMakeLists.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt index 2ed246a96d..9784366f11 100644 --- a/source/adios2/CMakeLists.txt +++ b/source/adios2/CMakeLists.txt @@ -349,6 +349,29 @@ install(FILES common/ADIOSMacros.h common/ADIOSTypes.h common/ADIOSTypes.inl DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2/common COMPONENT adios2_core-development ) +install(DIRECTORY core/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2/core COMPONENT adios2_core-development + FILES_MATCHING PATTERN "*.h" +) + +install(DIRECTORY engine/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2/engine COMPONENT adios2_core-development + FILES_MATCHING PATTERN "*/*.h" + PATTERN "*/*.inl" +) + +install(DIRECTORY helper/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2/helper COMPONENT adios2_core-development + FILES_MATCHING PATTERN "*.h" + PATTERN "*.inl" +) + +install(DIRECTORY toolkit/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2/toolkit COMPONENT adios2_core-development + FILES_MATCHING PATTERN "*/*.h" + PATTERN "*/*.inl" +) + # Library installation install(TARGETS adios2_core ${maybe_adios2_core_mpi} EXPORT adios2Exports RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT adios2_core-runtime From 5be2de10a5a21b90ef922c574a89853ea38f5ed9 Mon Sep 17 00:00:00 2001 From: Caitlin Ross Date: Wed, 7 Jul 2021 16:02:31 -0400 Subject: [PATCH 4/6] add install test for plugin engine --- testing/install/CMakeLists.txt | 2 ++ testing/install/plugin/CMakeLists.txt | 28 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 testing/install/plugin/CMakeLists.txt diff --git a/testing/install/CMakeLists.txt b/testing/install/CMakeLists.txt index cd8481d942..9f4e5cf599 100644 --- a/testing/install/CMakeLists.txt +++ b/testing/install/CMakeLists.txt @@ -109,3 +109,5 @@ if(NOT WIN32) endif() endif() endif() + +add_install_cmake_test(plugin) diff --git a/testing/install/plugin/CMakeLists.txt b/testing/install/plugin/CMakeLists.txt new file mode 100644 index 0000000000..e566715800 --- /dev/null +++ b/testing/install/plugin/CMakeLists.txt @@ -0,0 +1,28 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +cmake_minimum_required(VERSION 3.6) +project(adios_plugin_test CXX) +enable_testing() + +find_package(adios2 REQUIRED) + +# add write test +add_executable(adios_plugin_write_test + ../../../examples/plugins/engine/examplePluginEngine_write.cpp + ../../../examples/plugins/engine/ExampleWritePlugin.cpp +) +target_link_libraries(adios_plugin_write_test adios2::cxx11 adios2::core) +add_test(NAME adios_plugin_write_test COMMAND adios_plugin_write_test) + +# add read test +add_executable(adios_plugin_read_test + ../../../examples/plugins/engine/examplePluginEngine_read.cpp + ../../../examples/plugins/engine/ExampleReadPlugin.cpp +) +target_link_libraries(adios_plugin_read_test adios2::cxx11 adios2::core) +add_test(NAME adios_plugin_read_test COMMAND adios_plugin_read_test) +set_tests_properties(adios_plugin_read_test PROPERTIES + DEPENDS adios_plugin_write_test) From e9d402e17e28693ee0cbf10f593c1bd95768f45e Mon Sep 17 00:00:00 2001 From: Caitlin Ross Date: Thu, 8 Jul 2021 11:11:03 -0400 Subject: [PATCH 5/6] plugin engine: user guide docs --- docs/user_guide/source/conf.py | 1 + docs/user_guide/source/engines/engines.rst | 1 + docs/user_guide/source/engines/plugin.rst | 97 ++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 docs/user_guide/source/engines/plugin.rst diff --git a/docs/user_guide/source/conf.py b/docs/user_guide/source/conf.py index fc6fbfb4ef..0924fc2155 100644 --- a/docs/user_guide/source/conf.py +++ b/docs/user_guide/source/conf.py @@ -140,6 +140,7 @@ 'engines/sst.rst', 'engines/inline.rst', 'engines/null.rst', + 'engines/plugin.rst', # 'engines/engines.rst', # 'faq/faq.rst', ] diff --git a/docs/user_guide/source/engines/engines.rst b/docs/user_guide/source/engines/engines.rst index 0c74f9105c..63390de334 100644 --- a/docs/user_guide/source/engines/engines.rst +++ b/docs/user_guide/source/engines/engines.rst @@ -24,4 +24,5 @@ Parameters are passed at: .. include:: dataman.rst .. include:: inline.rst .. include:: null.rst +.. include:: plugin.rst .. include:: virtual_engines.rst diff --git a/docs/user_guide/source/engines/plugin.rst b/docs/user_guide/source/engines/plugin.rst new file mode 100644 index 0000000000..28815f2f26 --- /dev/null +++ b/docs/user_guide/source/engines/plugin.rst @@ -0,0 +1,97 @@ +************* +Plugin Engine +************* + +The ``Plugin`` engine enables the ability to load an engine located in a separate library. +Your plugin class needs to inherit from the ``PluginEngineInterface`` class in the ``adios2/engine/plugin/PluginEngineInterface.h`` header. +Depending on the type of engine you want to implement, you'll need to override a number of methods that are inherited from the ``adios2::core::Engine`` class. +These are briefly described in the following table. +More detailed documentation can be found in ``adios2/core/Engine.h``. + +========================= ===================== =========================================================== + **Method** **Engine Type** **Description** +========================= ===================== =========================================================== +``BeginStep()`` Read/Write Indicates the beginning of a step +``EndStep()`` Read/Write Indicates the end of a step +``CurrentStep()`` Read/Write Returns current step info +``DoClose()`` Read/Write Close a particular transport +``Init()`` Read/Write Engine initialization +``InitParameters()`` Read/Write Initialize parameters +``InitTransports()`` Read/Write Initialize transports +``PerformPuts()`` Write Execute all deferred mode ``Put`` +``Flush()`` Write Flushes data and metadata to a transport +``DoPut()`` Write Implementation for ``Put`` +``DoPutSync()`` Write Implementation for ``Put`` (Sync mode) +``DoPutDeferred()`` Write Implementation for ``Put`` (Deferred Mode) +``PerformGets()`` Read Execute all deferred mode ``Get`` +``DoGetSync()`` Read Implementation for ``Get`` (Sync mode) +``DoGetDeferred()`` Read Implementation for ``Get`` (Deferred Mode) +========================= ===================== =========================================================== + +Examples showing how to implement an engine plugin can be found in ``examples/plugins/engine``. +An example write engine is ``ExampleWritePlugin.h``, while an example read engine is in ``ExampleReadPlugin.h``. +The writer is a simple file writing engine that creates a directory (called ``ExamplePlugin`` by default) and writes variable information to vars.txt and actual data to data.txt. +The reader example reads the files output by the writer example. + +In addition to implementing the methods above, you'll need to implement ``EngineCreate()`` and ``EngineDestroy`` functions so the Plugin Engine can create/destroy the engine object. +Because of C++ name mangling, you'll need to use ``extern "C"``. +Looking at ``ExampleWritePlugin.h``, this looks like: + +.. code-block:: c++ + + extern "C" { + + adios2::core::engine::ExampleWritePlugin * + EngineCreate(adios2::core::IO &io, const std::string &name, + const adios2::Mode mode, adios2::helper::Comm comm) + { + return new adios2::core::engine::ExampleWritePlugin(io, name, mode, + comm.Duplicate()); + } + + void EngineDestroy(adios2::core::engine::ExampleWritePlugin * obj) + { + delete obj; + } + + } + +To build your plugin, your CMake should look something like: + +.. code-block:: cmake + + find_package(ADIOS2 REQUIRED) + set(BUILD_SHARED_LIBS ON) + add_library(PluginEngineWrite + ExampleWritePlugin.cpp + ) + target_link_libraries(PluginEngineWrite adios2::cxx11 adios2::core) + +When using the Plugin Engine, ADIOS will check for your plugin at the path specified in the ``ADIOS2_PLUGIN_PATH`` environment variable. +If ``ADIOS2_PLUGIN_PATH`` is not set, ADIOS will warn you about it, and then look for your plugin in the current working directory. + +The following steps show how to use your engine plugin in your application. +``examplePluginEngine_write.cpp`` and ``examplePluginEngine_read.cpp`` are an example of how to use the engine plugins described above. +The key steps to use your plugin are: + +1. Set engine to ``Plugin``. i.e.: + +.. code-block:: c++ + + io.SetEngine("Plugin"); + +2. Set ``PluginName`` (optional) and ``PluginLibrary`` (required) parameters. + If you don't set ``PluginName``, the Plugin Engine will give your plugin a default name of ``UserPlugin``. + In the write example, this looks like + +.. code-block:: c++ + + io.SetParameters({{"PluginName", "WritePlugin"}}); + io.SetParameters({{"PluginLibrary", "PluginEngineWrite"}}); + +.. note:: + You don't need to add the ``lib`` prefix or the shared library ending (e.g., ``.so``, ``.dll``, etc.). + ADIOS will add these when searching for your plugin library. + +At this point you can open the engine and use it as you would any other ADIOS engine. +You also shouldn't need to make any changes to your CMake files for your application. From e74e33a91b446623a7ec1cefb5d8adca64b32d8f Mon Sep 17 00:00:00 2001 From: Caitlin Ross Date: Mon, 25 Oct 2021 16:20:38 -0400 Subject: [PATCH 6/6] plugin engine: remove registration api and add env var --- docs/user_guide/source/engines/plugin.rst | 6 +- examples/plugins/engine/CMakeLists.txt | 16 +++- examples/plugins/engine/ExampleReadPlugin.cpp | 14 +++ examples/plugins/engine/ExampleReadPlugin.h | 9 ++ .../plugins/engine/ExampleWritePlugin.cpp | 16 ++++ examples/plugins/engine/ExampleWritePlugin.h | 9 ++ .../engine/examplePluginEngine_read.cpp | 10 +- .../engine/examplePluginEngine_write.cpp | 10 +- source/adios2/engine/plugin/PluginEngine.cpp | 93 +++++++------------ source/adios2/engine/plugin/PluginEngine.h | 21 ----- source/adios2/engine/plugin/PluginEngine.inl | 44 --------- source/adios2/helper/adiosDynamicBinder.cpp | 22 ++++- source/adios2/helper/adiosDynamicBinder.h | 1 + testing/install/plugin/CMakeLists.txt | 18 +++- 14 files changed, 138 insertions(+), 151 deletions(-) delete mode 100644 source/adios2/engine/plugin/PluginEngine.inl diff --git a/docs/user_guide/source/engines/plugin.rst b/docs/user_guide/source/engines/plugin.rst index 28815f2f26..5f9f38f388 100644 --- a/docs/user_guide/source/engines/plugin.rst +++ b/docs/user_guide/source/engines/plugin.rst @@ -68,7 +68,7 @@ To build your plugin, your CMake should look something like: target_link_libraries(PluginEngineWrite adios2::cxx11 adios2::core) When using the Plugin Engine, ADIOS will check for your plugin at the path specified in the ``ADIOS2_PLUGIN_PATH`` environment variable. -If ``ADIOS2_PLUGIN_PATH`` is not set, ADIOS will warn you about it, and then look for your plugin in the current working directory. +If ``ADIOS2_PLUGIN_PATH`` is not set, and a path is not specified in the settings for the Plugin Engine (see below steps for using a plugin in your application), then the usual ``dlopen`` search is performed (see `dlopen man page `_). The following steps show how to use your engine plugin in your application. ``examplePluginEngine_write.cpp`` and ``examplePluginEngine_read.cpp`` are an example of how to use the engine plugins described above. @@ -88,10 +88,14 @@ The key steps to use your plugin are: io.SetParameters({{"PluginName", "WritePlugin"}}); io.SetParameters({{"PluginLibrary", "PluginEngineWrite"}}); + // also possible to use the path here instead of setting ADIOS2_PLUGIN_PATH + // io.SetParameters({{"PluginLibrary", "/path/to/libPluginEngineWrite.so"}}) .. note:: You don't need to add the ``lib`` prefix or the shared library ending (e.g., ``.so``, ``.dll``, etc.). ADIOS will add these when searching for your plugin library. + If you do at the prefix/suffix, ADIOS should still be able to find your plugin. + At this point you can open the engine and use it as you would any other ADIOS engine. You also shouldn't need to make any changes to your CMake files for your application. diff --git a/examples/plugins/engine/CMakeLists.txt b/examples/plugins/engine/CMakeLists.txt index a4f3e812c2..e49ccb6d55 100644 --- a/examples/plugins/engine/CMakeLists.txt +++ b/examples/plugins/engine/CMakeLists.txt @@ -3,14 +3,22 @@ # accompanying file Copyright.txt for details. #------------------------------------------------------------------------------# +add_library(PluginEngineWriteExample + ExampleWritePlugin.cpp +) +target_link_libraries(PluginEngineWriteExample adios2::cxx11 adios2_core) + +add_library(PluginEngineReadExample + ExampleReadPlugin.cpp +) +target_link_libraries(PluginEngineReadExample adios2::cxx11 adios2_core) + add_executable(examplePluginEngine_write examplePluginEngine_write.cpp - ExampleWritePlugin.h ExampleWritePlugin.cpp ) -target_link_libraries(examplePluginEngine_write adios2::cxx11 adios2_core) +target_link_libraries(examplePluginEngine_write adios2::cxx11) add_executable(examplePluginEngine_read examplePluginEngine_read.cpp - ExampleReadPlugin.h ExampleReadPlugin.cpp ) -target_link_libraries(examplePluginEngine_read adios2::cxx11 adios2_core) +target_link_libraries(examplePluginEngine_read adios2::cxx11) diff --git a/examples/plugins/engine/ExampleReadPlugin.cpp b/examples/plugins/engine/ExampleReadPlugin.cpp index cb29f28a29..e0a1d8b2a6 100644 --- a/examples/plugins/engine/ExampleReadPlugin.cpp +++ b/examples/plugins/engine/ExampleReadPlugin.cpp @@ -133,3 +133,17 @@ void ExampleReadPlugin::DoClose(const int transportIndex) {} } // end namespace engine } // end namespace core } // end namespace adios2 + +extern "C" { + +adios2::core::engine::ExampleReadPlugin *EngineCreate(adios2::core::IO &io, + const std::string &name, + const adios2::Mode mode, + adios2::helper::Comm comm) +{ + return new adios2::core::engine::ExampleReadPlugin(io, name, mode, + comm.Duplicate()); +} + +void EngineDestroy(adios2::core::engine::ExampleReadPlugin *obj) { delete obj; } +} diff --git a/examples/plugins/engine/ExampleReadPlugin.h b/examples/plugins/engine/ExampleReadPlugin.h index b40efa6ce0..620fc1486c 100644 --- a/examples/plugins/engine/ExampleReadPlugin.h +++ b/examples/plugins/engine/ExampleReadPlugin.h @@ -80,4 +80,13 @@ class ExampleReadPlugin : public PluginEngineInterface } // end namespace engine } // end namespace core } // end namespace adios2 + +extern "C" { + +adios2::core::engine::ExampleReadPlugin * +EngineCreate(adios2::core::IO &io, const std::string &name, + const adios2::Mode mode, adios2::helper::Comm comm); +void EngineDestroy(adios2::core::engine::ExampleReadPlugin *obj); +} + #endif /* EXAMPLEREADPLUGIN_H_ */ diff --git a/examples/plugins/engine/ExampleWritePlugin.cpp b/examples/plugins/engine/ExampleWritePlugin.cpp index 48649827b6..cc18042e7e 100644 --- a/examples/plugins/engine/ExampleWritePlugin.cpp +++ b/examples/plugins/engine/ExampleWritePlugin.cpp @@ -113,3 +113,19 @@ void ExampleWritePlugin::WriteVarsFromIO() } // end namespace engine } // end namespace core } // end namespace adios2 + +extern "C" { + +adios2::core::engine::ExampleWritePlugin * +EngineCreate(adios2::core::IO &io, const std::string &name, + const adios2::Mode mode, adios2::helper::Comm comm) +{ + return new adios2::core::engine::ExampleWritePlugin(io, name, mode, + comm.Duplicate()); +} + +void EngineDestroy(adios2::core::engine::ExampleWritePlugin *obj) +{ + delete obj; +} +} diff --git a/examples/plugins/engine/ExampleWritePlugin.h b/examples/plugins/engine/ExampleWritePlugin.h index 732130deaa..e13eecb184 100644 --- a/examples/plugins/engine/ExampleWritePlugin.h +++ b/examples/plugins/engine/ExampleWritePlugin.h @@ -81,4 +81,13 @@ class ExampleWritePlugin : public PluginEngineInterface } // end namespace engine } // end namespace core } // end namespace adios2 + +extern "C" { + +adios2::core::engine::ExampleWritePlugin * +EngineCreate(adios2::core::IO &io, const std::string &name, + const adios2::Mode mode, adios2::helper::Comm comm); +void EngineDestroy(adios2::core::engine::ExampleWritePlugin *obj); +} + #endif /* EXAMPLEWRITEPLUGIN_H_ */ diff --git a/examples/plugins/engine/examplePluginEngine_read.cpp b/examples/plugins/engine/examplePluginEngine_read.cpp index d9c6b95317..68e980c798 100644 --- a/examples/plugins/engine/examplePluginEngine_read.cpp +++ b/examples/plugins/engine/examplePluginEngine_read.cpp @@ -15,9 +15,6 @@ #include #include "adios2.h" -#include "adios2/engine/plugin/PluginEngine.h" - -#include "ExampleReadPlugin.h" void testStreaming(adios2::Engine &reader, std::vector &myFloats, adios2::Variable &var) @@ -58,10 +55,6 @@ int main(int argc, char *argv[]) std::vector myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - /** Register Plugin with the PluginEngine **/ - adios2::core::engine::PluginEngine::RegisterPlugin< - adios2::core::engine::ExampleReadPlugin>("MyPlugin"); - try { /** ADIOS class factory of IO class objects */ @@ -73,7 +66,8 @@ int main(int argc, char *argv[]) /** Engine derived class, spawned to start IO operations */ io.SetEngine("Plugin"); - io.SetParameters({{"PluginName", "MyPlugin"}}); + io.SetParameters({{"PluginName", "ReadPlugin"}}); + io.SetParameters({{"PluginLibrary", "PluginEngineRead"}}); adios2::Engine reader = io.Open("TestPlugin", adios2::Mode::Read); auto var = io.InquireVariable("data"); diff --git a/examples/plugins/engine/examplePluginEngine_write.cpp b/examples/plugins/engine/examplePluginEngine_write.cpp index 5c87f4a7e1..9110995cd3 100644 --- a/examples/plugins/engine/examplePluginEngine_write.cpp +++ b/examples/plugins/engine/examplePluginEngine_write.cpp @@ -15,9 +15,6 @@ #include #include "adios2.h" -#include "adios2/engine/plugin/PluginEngine.h" - -#include "ExampleWritePlugin.h" void testStreaming(adios2::Engine &writer, std::vector &myFloats, adios2::Variable &var) @@ -49,10 +46,6 @@ int main(int argc, char *argv[]) std::vector myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; const std::size_t Nx = myFloats.size(); - /** Register Plugin with the PluginEngine **/ - adios2::core::engine::PluginEngine::RegisterPlugin< - adios2::core::engine::ExampleWritePlugin>("MyPlugin"); - try { /** ADIOS class factory of IO class objects */ @@ -69,7 +62,8 @@ int main(int argc, char *argv[]) /** Engine derived class, spawned to start IO operations */ io.SetEngine("Plugin"); - io.SetParameters({{"PluginName", "MyPlugin"}}); + io.SetParameters({{"PluginName", "WritePlugin"}}); + io.SetParameters({{"PluginLibrary", "PluginEngineWrite"}}); adios2::Engine writer = io.Open("TestPlugin", adios2::Mode::Write); if (streaming) diff --git a/source/adios2/engine/plugin/PluginEngine.cpp b/source/adios2/engine/plugin/PluginEngine.cpp index fe72c9ebd6..37395a9e7d 100644 --- a/source/adios2/engine/plugin/PluginEngine.cpp +++ b/source/adios2/engine/plugin/PluginEngine.cpp @@ -13,13 +13,14 @@ #include "PluginEngineInterface.h" #include -#include #include #include #include #include "adios2/helper/adiosDynamicBinder.h" +#include + namespace adios2 { namespace core @@ -31,27 +32,12 @@ namespace engine struct PluginEngine::Impl { - using Registry = - std::map>; - static Registry m_Registry; - - std::string m_PluginName; + std::string m_PluginName = "UserPlugin"; std::unique_ptr m_Binder; EngineCreateFun m_HandleCreate; EngineDestroyFun m_HandleDestroy; PluginEngineInterface *m_Plugin = nullptr; }; -PluginEngine::Impl::Registry PluginEngine::Impl::m_Registry; - -/******************************************************************************/ - -void PluginEngine::RegisterPlugin(const std::string pluginName, - EngineCreateFun create, - EngineDestroyFun destroy) -{ - PluginEngine::Impl::m_Registry.emplace(pluginName, - std::make_pair(create, destroy)); -} /******************************************************************************/ @@ -80,56 +66,43 @@ void PluginEngine::EndStep() { m_Impl->m_Plugin->EndStep(); } void PluginEngine::Init() { auto paramPluginNameIt = m_IO.m_Parameters.find("PluginName"); - if (paramPluginNameIt == m_IO.m_Parameters.end()) + if (paramPluginNameIt != m_IO.m_Parameters.end()) + { + m_Impl->m_PluginName = paramPluginNameIt->second; + } + + std::string pluginPath; + adios2sys::SystemTools::GetEnv("ADIOS2_PLUGIN_PATH", pluginPath); + + auto paramPluginLibraryIt = m_IO.m_Parameters.find("PluginLibrary"); + if (paramPluginLibraryIt == m_IO.m_Parameters.end()) { - throw std::invalid_argument("PluginEngine: PluginName must be " - "specified in engine parameters"); + throw std::invalid_argument( + "PluginEngine: PluginLibrary must be specified in " + "engine parameters if no PluginName " + "is specified"); } - m_Impl->m_PluginName = paramPluginNameIt->second; + std::string &pluginLibrary = paramPluginLibraryIt->second; - // First we check to see if we can find the plugin currently registerd - auto registryEntryIt = - PluginEngine::Impl::m_Registry.find(m_Impl->m_PluginName); + m_Impl->m_Binder.reset( + new helper::DynamicBinder(pluginLibrary, pluginPath)); - if (registryEntryIt != PluginEngine::Impl::m_Registry.end()) + m_Impl->m_HandleCreate = reinterpret_cast( + m_Impl->m_Binder->GetSymbol("EngineCreate")); + if (!m_Impl->m_HandleCreate) { - m_Impl->m_HandleCreate = registryEntryIt->second.first; - m_Impl->m_HandleDestroy = registryEntryIt->second.second; + throw std::runtime_error("PluginEngine: Unable to locate " + "EngineCreate symbol in specified plugin " + "library"); } - else + + m_Impl->m_HandleDestroy = reinterpret_cast( + m_Impl->m_Binder->GetSymbol("EngineDestroy")); + if (!m_Impl->m_HandleDestroy) { - // It's not currently registered so try to load it from a shared - // library - // - auto paramPluginLibraryIt = m_IO.m_Parameters.find("PluginLibrary"); - if (paramPluginLibraryIt == m_IO.m_Parameters.end()) - { - throw std::invalid_argument( - "PluginEngine: PluginLibrary must be specified in " - "engine parameters if no PluginName " - "is specified"); - } - std::string &pluginLibrary = paramPluginLibraryIt->second; - - m_Impl->m_Binder.reset(new helper::DynamicBinder(pluginLibrary)); - - m_Impl->m_HandleCreate = reinterpret_cast( - m_Impl->m_Binder->GetSymbol("EngineCreate")); - if (!m_Impl->m_HandleCreate) - { - throw std::runtime_error("PluginEngine: Unable to locate " - "EngineCreate symbol in specified plugin " - "library"); - } - - m_Impl->m_HandleDestroy = reinterpret_cast( - m_Impl->m_Binder->GetSymbol("EngineDestroy")); - if (!m_Impl->m_HandleDestroy) - { - throw std::runtime_error("PluginEngine: Unable to locate " - "EngineDestroy symbol in specified plugin " - "library"); - } + throw std::runtime_error("PluginEngine: Unable to locate " + "EngineDestroy symbol in specified plugin " + "library"); } } diff --git a/source/adios2/engine/plugin/PluginEngine.h b/source/adios2/engine/plugin/PluginEngine.h index 3e8c5a8172..74c74ce370 100644 --- a/source/adios2/engine/plugin/PluginEngine.h +++ b/source/adios2/engine/plugin/PluginEngine.h @@ -18,14 +18,12 @@ #include // for unique_ptr #include // for string #include // for add_pointer -#include // for vector #include "adios2/common/ADIOSMacros.h" #include "adios2/common/ADIOSTypes.h" #include "adios2/core/Engine.h" #include "adios2/core/IO.h" #include "adios2/core/Variable.h" -#include "adios2/core/VariableCompound.h" #include "adios2/helper/adiosComm.h" namespace adios2 @@ -49,23 +47,6 @@ class PluginEngine : public Engine using EngineDestroyFun = std::function::type>; - static void RegisterPlugin(const std::string pluginName, - EngineCreateFun create, - EngineDestroyFun destroy); - static void RegisterPlugin(const std::string pluginName, - EngineCreatePtr create, EngineDestroyPtr destroy) - { - RegisterPlugin(pluginName, EngineCreateFun(create), - EngineDestroyFun(destroy)); - } - - // This is just a shortcut method to handle the case where the class type is - // directly available to the caller so a simple new and delete call is - // sufficient to create and destroy the engine object - template - static void RegisterPlugin(const std::string name); - -public: PluginEngine(IO &io, const std::string &name, const Mode mode, helper::Comm comm); virtual ~PluginEngine(); @@ -99,6 +80,4 @@ class PluginEngine : public Engine } // end namespace core } // end namespace adios2 -#include "PluginEngine.inl" - #endif /* ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ */ diff --git a/source/adios2/engine/plugin/PluginEngine.inl b/source/adios2/engine/plugin/PluginEngine.inl deleted file mode 100644 index 3006e45c53..0000000000 --- a/source/adios2/engine/plugin/PluginEngine.inl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Distributed under the OSI-approved Apache License, Version 2.0. See - * accompanying file Copyright.txt for details. - * - * PluginEngine.h Support for an engine implemented outside libadios2 - * - * Created on: July 5, 2021 - * Author: Chuck Atkins - * Caitlin Ross - */ - -#ifndef ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ -#define ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ -#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ -#error "Inline file should only be included from it's header, never on it's own" -#endif - -#include "PluginEngine.h" - -namespace adios2 -{ -namespace core -{ -namespace engine -{ - -template -void PluginEngine::RegisterPlugin(const std::string name) -{ - EngineCreateFun createFun = - [](IO &io, const std::string &name, const Mode openMode, - helper::Comm comm) -> PluginEngineInterface * { - return new T(io, name, openMode, comm.Duplicate()); - }; - EngineDestroyFun destroyFun = [](Engine *obj) -> void { delete obj; }; - - RegisterPlugin(name, createFun, destroyFun); -} - -} // end namespace engine -} // end namespace core -} // end namespace adios2 - -#endif // ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ diff --git a/source/adios2/helper/adiosDynamicBinder.cpp b/source/adios2/helper/adiosDynamicBinder.cpp index 42d7cfcc0b..cab7a8ce9e 100644 --- a/source/adios2/helper/adiosDynamicBinder.cpp +++ b/source/adios2/helper/adiosDynamicBinder.cpp @@ -18,6 +18,7 @@ #include // for vector #include +#include namespace adios2 { @@ -30,6 +31,12 @@ struct DynamicBinder::Impl }; DynamicBinder::DynamicBinder(std::string libName) +{ + DynamicBinder(libName, ""); +} + +DynamicBinder::DynamicBinder(std::string libName, std::string libPath) +: m_Impl(new Impl) { std::vector libPrefixes; libPrefixes.emplace_back(""); @@ -39,6 +46,7 @@ DynamicBinder::DynamicBinder(std::string libName) #endif std::vector libSuffixes; + libSuffixes.emplace_back(""); #ifdef __APPLE__ libSuffixes.emplace_back(".dylib"); libSuffixes.emplace_back(".so"); @@ -61,7 +69,19 @@ DynamicBinder::DynamicBinder(std::string libName) { for (const std::string &suffix : libSuffixes) { - fileName = prefix + libName + suffix; + if (!libPath.empty()) + { + fileName = libPath + "/" + prefix + libName + suffix; + // Slashes in fileName is correct for unix-like systems + // ConvertToOutputPath() will change slashes if we're running on + // a Windows system + fileName = + adios2sys::SystemTools::ConvertToOutputPath(fileName); + } + else + { + fileName = prefix + libName + suffix; + } m_Impl->m_LibraryHandle = adios2sys::DynamicLoader::OpenLibrary(fileName); searchedLibs.push_back(fileName); diff --git a/source/adios2/helper/adiosDynamicBinder.h b/source/adios2/helper/adiosDynamicBinder.h index 55247a0c9a..21f8f9d9de 100644 --- a/source/adios2/helper/adiosDynamicBinder.h +++ b/source/adios2/helper/adiosDynamicBinder.h @@ -27,6 +27,7 @@ class DynamicBinder public: DynamicBinder(std::string libName); + DynamicBinder(std::string libName, std::string libPath); ~DynamicBinder(); VoidSymbolPointer GetSymbol(std::string symbolName); diff --git a/testing/install/plugin/CMakeLists.txt b/testing/install/plugin/CMakeLists.txt index e566715800..2757112dba 100644 --- a/testing/install/plugin/CMakeLists.txt +++ b/testing/install/plugin/CMakeLists.txt @@ -9,20 +9,30 @@ enable_testing() find_package(adios2 REQUIRED) +option(BUILD_SHARED_LIBS "build shared libs" ON) + +add_library(PluginEngineWrite + ../../../examples/plugins/engine/ExampleWritePlugin.cpp +) +target_link_libraries(PluginEngineWrite adios2::cxx11 adios2::core) + +add_library(PluginEngineRead + ../../../examples/plugins/engine/ExampleReadPlugin.cpp +) +target_link_libraries(PluginEngineRead adios2::cxx11 adios2::core) + # add write test add_executable(adios_plugin_write_test ../../../examples/plugins/engine/examplePluginEngine_write.cpp - ../../../examples/plugins/engine/ExampleWritePlugin.cpp ) -target_link_libraries(adios_plugin_write_test adios2::cxx11 adios2::core) +target_link_libraries(adios_plugin_write_test adios2::cxx11) add_test(NAME adios_plugin_write_test COMMAND adios_plugin_write_test) # add read test add_executable(adios_plugin_read_test ../../../examples/plugins/engine/examplePluginEngine_read.cpp - ../../../examples/plugins/engine/ExampleReadPlugin.cpp ) -target_link_libraries(adios_plugin_read_test adios2::cxx11 adios2::core) +target_link_libraries(adios_plugin_read_test adios2::cxx11) add_test(NAME adios_plugin_read_test COMMAND adios_plugin_read_test) set_tests_properties(adios_plugin_read_test PROPERTIES DEPENDS adios_plugin_write_test)