C++ Morpheus Modules

See Simple Python Module for an introduction to Morpheus modules.

The following example will create a simple C++ module that passes through the input data without modification. This module will be written in C++ and would be compiled into the morpheus core library.

Note: One thing that is different with respect to c++ modules, is that they are assumed to be stateless by default, meaning that the module itself can be released after the initialize function as been called. If you need a module whose state is persisted across the lifetime of the pipeline, you will also need to inherit from the PersistentModule class, which will cause the pipeline to hold a reference to the module until the pipeline is destroyed.

my_test_module.hpp

Copy
Copied!
            

#pragma once #include <mrc/modules/properties/persistent.hpp> #include <mrc/modules/segment_modules.hpp> #include <nlohmann/json.hpp> namespace morpheus { #pragma GCC visibility push(default) class MyTestModule: public mrc::modules::SegmentModule, public mrc::modules::PersistentModule { using type_t = MyTestModule; public: DataLoaderModule(std::string module_name); DataLoaderModule(std::string module_name, nlohmann::json _config); protected: void initialize(mrc::segment::Builder& builder) override; std::string module_type_name() const override; private: int my_persistent_value{0}; }; #pragma GCC visibility pop } // namespace morpheus

my_test_module.cpp

Copy
Copied!
            

#include <mrc/modules/segment_modules.hpp> #include <mrc/segment/builder.hpp> #include <mrc/utils/type_utils.hpp> #include <nlohmann/json.hpp> #include <string> namespace morpheus { MyTestModule::MyTestModule(std::string module_name) : SegmentModule(module_name) {} MyTestModule::MyTestModule(std::string module_name, nlohmann::json _config) : SegmentModule(std::move(module_name), std::move(_config)) {} void MyTestModule::initialize(mrc::segment::Builder& builder) { auto passthrough_node = builder.make_node<std::shared_ptr<MyDataType>>("passthrough_node", rxcpp::operators::map([this](std::shared_ptr<MyDataType> data) { return data; })); register_input_port("input_0", passthrough_node); register_output_port("output_0", passthrough_node); } std::string MyTestModule::module_type_name() const { return std::string(::mrc::boost_type_name<type_t>()); } }

my_test_module_registration.cpp

Copy
Copied!
            

#include "mrc/modules/module_registry.hpp" #include "my_test_module.hpp" int main(int argc, char** argv) { const std::vector<unsigned int> release_version = {1, 0, 0}; auto module_constructor = [](std::string module_name, nlohmann::json config) { return std::make_shared<morpheus::MyTestModule>(module_name, config); }; ModuleRegistry::register_module("my_test_module", "my_module_namespace", release_version, module_constructor); }

Dynamic Module Creation and Loading

Copy
Copied!
            

#include "mrc/version.hpp" #include "mrc/modules/module_registry.hpp" #include "my_test_module.hpp" extern "C" { const std::vector<unsigned int> TestModuleVersion{mrc_VERSION_MAJOR, mrc_VERSION_MINOR, mrc_VERSION_PATCH}; const char* MODULES[] = {"my_test_module::my_module_namespace"}; bool MRC_MODULE_entrypoint_load() // NOLINT { using namespace mrc::modules; try { ModuleRegistry::register_module( "my_test_module", "my_module_namespace" TestModuleVersion, [](std::string module_name, nlohmann::json config) { return std::make_shared<mrc::modules::MyTestModule>(std::move(module_name), std::move(config)); }); } catch (...) { return false; } return true; } bool MRC_MODULE_entrypoint_unload() // NOLINT { using namespace mrc::modules; try { ModuleRegistry::unregister_module("my_test_module", "my_module_namespace"); } catch (...) { return false; } return true; } unsigned int MRC_MODULE_entrypoint_list(const char** result) // NOLINT { *result = (const char*)(&MODULES); return 1; // Number of modules }

The above code is an example of how to declare a shared module that can be loaded at runtime. If we assume this snippet is compile into my_test_module.so, we can load dynamically load the module at runtime using the following:

Copy
Copied!
            

#include "mrc/modules/module_registry.hpp" std::string get_modules_path() { return std::string{YOUR_MODULES_PATH}; } int main(int argc, char** argv) { using namespace mrc::modules; auto plugin = PluginModule::create_or_acquire("my_test_module.so"); plugin->set_library_directory(get_modules_path()); plugin->load(); std::string module_namespace{"my_module_namespace"}; std::string module_name{"my_test_module"}; ModuleRegistry::contains_namespace(module_namespace); // Should be true ModuleRegistry::contains(module_name, module_namespace); // Should be true }

© Copyright 2023, NVIDIA. Last updated on Apr 11, 2023.