diff --git a/libs/qec/lib/decoders/plugins/example/CMakeLists.txt b/libs/qec/lib/decoders/plugins/example/CMakeLists.txt index 9105577..486bad0 100644 --- a/libs/qec/lib/decoders/plugins/example/CMakeLists.txt +++ b/libs/qec/lib/decoders/plugins/example/CMakeLists.txt @@ -7,42 +7,53 @@ # ============================================================================ # cmake_minimum_required(VERSION 3.28 FATAL_ERROR) -project(cudaq-qec-example) + +set(MODULE_NAME "cudaq-qec-example") + +project(${MODULE_NAME}) # Specify the source file for the plugin -set(PLUGIN_SRC +set(PLUGIN_SRC single_error_lut_example.cpp # single_error_lut_example2.cpp // add other decoder source files here plugin_exports.cpp ) # Create the shared library -add_library(cudaq-qec-example SHARED ${PLUGIN_SRC}) +add_library(${MODULE_NAME} SHARED ${PLUGIN_SRC}) # Set the include directories for dependencies -target_include_directories(cudaq-qec-example - PUBLIC - ${CMAKE_SOURCE_DIR}/libs/qec/include # Path to cudaq/qec/decoder.h - ${CMAKE_SOURCE_DIR}/libs/core/include # Path to cuda-qx/core/ (for tensor.h, extension points, etc) +target_include_directories(${MODULE_NAME} + PUBLIC + ${CMAKE_SOURCE_DIR}/libs/qec/include + ${CMAKE_SOURCE_DIR}/libs/core/include ) -# Link with required libraries (based on earlier CMake you shared) -target_link_libraries(cudaq-qec-example - PUBLIC - cudaqx-core # This could be from another library target, or pre-built if needed - cudaq::cudaq +# Link with required libraries +target_link_libraries(${MODULE_NAME} + PUBLIC + cudaqx-core + cudaq::cudaq cudaq::cudaq-spin - PRIVATE + PRIVATE cudaq::cudaq-common + cudaq-qec ) -# Place the shared library in the specified output directory -set_target_properties(cudaq-qec-example PROPERTIES +set_target_properties(${MODULE_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/plugins ) -# Set RPATH so that the shared libraries are properly resolved -set_target_properties(cudaq-qec-example PROPERTIES +# Set RPATH +set_target_properties(${MODULE_NAME} PROPERTIES BUILD_RPATH "$ORIGIN" INSTALL_RPATH "$ORIGIN:$ORIGIN/../lib" ) + +# Install +# ============================================================================== + +install(TARGETS ${MODULE_NAME} + COMPONENT qec-lib-plugins + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/libs/qec/lib/decoders/plugins/example/decoder_plugins_demo.cpp b/libs/qec/lib/decoders/plugins/example/decoder_plugins_demo.cpp index 390cfcc..0a434d5 100644 --- a/libs/qec/lib/decoders/plugins/example/decoder_plugins_demo.cpp +++ b/libs/qec/lib/decoders/plugins/example/decoder_plugins_demo.cpp @@ -21,13 +21,14 @@ #include #include "cudaq.h" -#include "decoder_plugins_loader.h" // required header to load the plugins #include "cudaq/qec/decoder.h" #include "cudaq/qec/experiments.h" +#include "decoder_plugins_loader.h" // required header to load the plugins int main() { auto steane = cudaq::qec::get_code("steane"); auto Hz = steane->get_parity_z(); + cudaqx::heterogeneous_map params; std::vector t_shape = Hz.shape(); std::cout << "Hz.shape():\n"; @@ -45,17 +46,10 @@ int main() { double p = 0.2; size_t nShots = 5; - DecoderFactory factory; - factory.load_plugins( - "."); // provide the abs path to the directory containing the plugins - auto plugin_names = factory.get_all_plugin_names(); - std::cout << "Decoder plugins contain the following decoders:\n"; - for (auto &name : plugin_names) { - std::cout << "-> " << name << "\n"; - } - cudaqx::heterogeneous_map params; - std::unique_ptr lut_decoder = - factory.create_decoder("create_single_error_lut_example", Hz, params); + // load the decoder plugins + load_plugins("."); + // create a decoder from the plugins + auto lut_decoder = cudaq::qec::get_decoder("single_error_lut_example", Hz); std::cout << "nShots: " << nShots << "\n"; diff --git a/libs/qec/lib/decoders/plugins/example/decoder_plugins_loader.h b/libs/qec/lib/decoders/plugins/example/decoder_plugins_loader.h index 71a0f75..544022b 100644 --- a/libs/qec/lib/decoders/plugins/example/decoder_plugins_loader.h +++ b/libs/qec/lib/decoders/plugins/example/decoder_plugins_loader.h @@ -12,137 +12,30 @@ #include #include #include -#include -#include -#include - -#include "cudaq.h" -#include "cudaq/qec/decoder.h" namespace fs = std::filesystem; -// Type definition for the creator function -using CreatorFunction = std::unique_ptr (*)( - const cudaqx::tensor &, const cudaqx::heterogeneous_map &); - -/** - * @brief Struct to manage loaded decoders. - * This struct holds the name, handle, and creator function of a decoder plugin. - */ -struct DecoderPlugin { - std::string name; - void *handle; - CreatorFunction creator; -}; - -/** - * @brief Factory class to manage and create decoder plugins. - * This class handles the loading of decoder plugins from shared libraries, - * and provides functionality to create decoders and retrieve plugin names. - */ -class DecoderFactory { -private: - std::vector plugins; - -public: - ~DecoderFactory() { - for (auto &plugin : plugins) { - if (plugin.handle) { - dlclose(plugin.handle); +/// @brief Load all shared libraries (.so) from the specified directory. +/// @param directory The directory where the shared libraries are located. +bool load_plugins(const std::string &directory) { + bool success = true; + for (const auto &entry : fs::directory_iterator(directory)) { + if (entry.path().extension() == ".so") { + std::cout << "Loading plugin: " << entry.path() << std::endl; + + // Open the shared library + void *handle = dlopen(entry.path().c_str(), RTLD_NOW); + if (!handle) { + std::cerr << "Failed to load plugin: " << entry.path() + << "Error: " << dlerror() << std::endl; + success = false; + } else { + // Close the shared library + dlclose(handle); } } } - - /** - * @brief Load plugins from a specified directory. - * This function scans the given directory for shared library files (.so) - * and loads them as decoder plugins. - * @param directory The directory to scan for plugins. - */ - void load_plugins(const std::string &directory) { - for (const auto &entry : fs::directory_iterator(directory)) { - // scan the directory and load all .so files - if (entry.path().extension() == ".so") { - std::cout << "Loading plugin: " << entry.path() << "\n"; - - void *handle = dlopen(entry.path().c_str(), RTLD_LAZY); - if (!handle) { - std::cerr << "Failed to load " << entry.path() << ": " << dlerror() - << "\n"; - continue; - } - - dlerror(); // Clear errors - using SymbolListFunction = const char *(*)(); - SymbolListFunction get_symbols = reinterpret_cast( - dlsym(handle, "get_exported_symbols")); - const char *dlsym_error = dlerror(); - if (dlsym_error) { - std::cerr << "dlsym failed to get 'get_exported_symbols': " - << dlsym_error << "\n"; - dlclose(handle); - continue; - } - - // Extract the list of symbols and split by comma if there are multiple - std::string symbols = get_symbols(); - std::vector symbol_list; - std::stringstream ss(symbols); - std::string item; - while (std::getline(ss, item, ',')) { - symbol_list.push_back(item); - } - - for (const auto &symbol : symbol_list) { - std::cout << "Looking for function: " << symbol << "\n"; - CreatorFunction creator = - reinterpret_cast(dlsym(handle, symbol.c_str())); - const char *dlsym_error = dlerror(); - if (!dlsym_error) { - plugins.push_back({symbol, handle, creator}); - std::cout << "Successfully loaded symbol: " << symbol << "\n"; - } else { - std::cerr << "dlsym failed to get symbol' " << symbol - << "': " << dlsym_error << "\n"; - } - } - } - } - } - - /** - * @brief Create a decoder using a specified plugin. - * This function creates a decoder by invoking the creator function of the - * specified plugin. - * @param plugin_name The name of the plugin to use. - * @param H The tensor to pass to the creator function. - * @param params The heterogeneous map to pass to the creator function. - * @return A unique pointer to the created decoder. - * @throws std::runtime_error if the plugin is not found. - */ - std::unique_ptr - create_decoder(const std::string &plugin_name, - const cudaqx::tensor &H, - const cudaqx::heterogeneous_map ¶ms) { - for (auto &plugin : plugins) { - if (plugin.name == plugin_name) { - return plugin.creator(H, params); - } - } - throw std::runtime_error("Decoder " + plugin_name + " not found."); - } - - /** - * @brief Returns a vector of string of available decoders - * @return A unique pointer to the created decoder. - */ - std::vector get_all_plugin_names() { - std::vector plugin_names; - for (auto &plugin : plugins) { - plugin_names.push_back(plugin.name); - } - return plugin_names; - } -}; + return success; +} #endif // DECODER_PLUGINS_LOADER_H \ No newline at end of file diff --git a/libs/qec/lib/decoders/plugins/example/plugin_exports.cpp b/libs/qec/lib/decoders/plugins/example/plugin_exports.cpp deleted file mode 100644 index 2cb345a..0000000 --- a/libs/qec/lib/decoders/plugins/example/plugin_exports.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 NVIDIA Corporation & Affiliates. * - * All rights reserved. * - * * - * This source code and the accompanying materials are made available under * - * the terms of the Apache License 2.0 which accompanies this distribution. * - ******************************************************************************/ - -#include "plugin_exports.h" - -extern "C" const char *get_exported_symbols() { - static std::string exported_symbols; - if (exported_symbols.empty()) { - std::ostringstream oss; - auto symbols = SymbolRegistry::instance().get_symbols(); - for (size_t i = 0; i < symbols.size(); ++i) { - oss << symbols[i]; - if (i != symbols.size() - 1) { - oss << ","; - } - } - exported_symbols = oss.str(); - } - return exported_symbols.c_str(); -} \ No newline at end of file diff --git a/libs/qec/lib/decoders/plugins/example/plugin_exports.h b/libs/qec/lib/decoders/plugins/example/plugin_exports.h deleted file mode 100644 index 498aa55..0000000 --- a/libs/qec/lib/decoders/plugins/example/plugin_exports.h +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 NVIDIA Corporation & Affiliates. * - * All rights reserved. * - * * - * This source code and the accompanying materials are made available under * - * the terms of the Apache License 2.0 which accompanies this distribution. * - ******************************************************************************/ - -#ifndef PLUGIN_EXPORTS_H -#define PLUGIN_EXPORTS_H - -#include -#include -#include -#include - -/** - * @brief Singleton class to store the list of symbols. - * This class ensures that there is only one instance of the symbol registry - * which can be accessed globally. - */ -class SymbolRegistry { -public: - static SymbolRegistry &instance() { - static SymbolRegistry registry; - return registry; - } - - void register_symbol(const std::string &symbol) { symbols.push_back(symbol); } - - std::vector get_symbols() const { return symbols; } - -private: - std::vector symbols; - - // Private constructor to prevent instantiation - SymbolRegistry() = default; - // Delete copy constructor and assignment operator to prevent copying. - SymbolRegistry(const SymbolRegistry &) = delete; - SymbolRegistry &operator=(const SymbolRegistry &) = delete; -}; - -/** - * @brief Macro to register a symbol at compile-time. - * @param symbol The symbol to be registered. - */ -#define REGISTER_DECODER(symbol) \ - static bool symbol##_registered = []() { \ - SymbolRegistry::instance().register_symbol(#symbol); \ - return true; \ - }() - -/** - * @brief Expose a C-style function to return a list of symbols. - * This function returns a comma-separated list of the registered symbols. - * @return A C-style string containing the list of registered symbols. - */ -extern "C" const char *get_exported_symbols(); - -#endif // PLUGIN_EXPORTS_H diff --git a/libs/qec/lib/decoders/plugins/example/single_error_lut_example.cpp b/libs/qec/lib/decoders/plugins/example/single_error_lut_example.cpp index a4fdb99..1df26ef 100644 --- a/libs/qec/lib/decoders/plugins/example/single_error_lut_example.cpp +++ b/libs/qec/lib/decoders/plugins/example/single_error_lut_example.cpp @@ -6,7 +6,6 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -#include "plugin_exports.h" // required for exporting the decoder as a shared library #include "cudaq/qec/decoder.h" #include #include @@ -79,24 +78,14 @@ class single_error_lut_example : public decoder { virtual ~single_error_lut_example() {} - // The following is not needed when compiling the decoder code as a plugin - // CUDAQ_EXTENSION_CUSTOM_CREATOR_FUNCTION( - // single_error_lut_example, static std::unique_ptr create( - // const cudaqx::tensor &H, - // const cudaqx::heterogeneous_map ¶ms) { - // return std::make_unique(H, params); - // }) + CUDAQ_EXTENSION_CUSTOM_CREATOR_FUNCTION( + single_error_lut_example, static std::unique_ptr create( + const cudaqx::tensor &H, + const cudaqx::heterogeneous_map ¶ms) { + return std::make_unique(H, params); + }) }; -// CUDAQ_REGISTER_TYPE(single_error_lut_example) +CUDAQ_REGISTER_TYPE(single_error_lut_example) } // namespace cudaq::qec - -// The following is required when compiling the decoder code as a plugin -extern "C" std::unique_ptr -create_single_error_lut_example(const cudaqx::tensor &H, - const cudaqx::heterogeneous_map ¶ms) { - return std::make_unique(H, params); -} - -REGISTER_DECODER(create_single_error_lut_example); \ No newline at end of file