Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion phlex/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,24 @@ cet_make_library(
phlex::configuration
)

install(FILES concurrency.hpp driver.hpp module.hpp source.hpp DESTINATION include/phlex)
cet_make_library(
LIBRARY_NAME
phlex_resource
EXPORT_NAME
resource
INTERFACE
NO_SOURCE
LIBRARIES
Boost::boost
Boost::json
phlex::core
phlex::configuration
)

install(
FILES concurrency.hpp driver.hpp module.hpp resource.hpp source.hpp
DESTINATION include/phlex
)
install(FILES detail/plugin_macros.hpp DESTINATION include/phlex/detail)

cet_make_library(
Expand Down
39 changes: 34 additions & 5 deletions phlex/app/load_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "phlex/core/framework_graph.hpp"
#include "phlex/driver.hpp"
#include "phlex/module.hpp"
#include "phlex/resource.hpp"
#include "phlex/source.hpp"

#include "boost/algorithm/string.hpp"
Expand Down Expand Up @@ -38,12 +39,22 @@ namespace phlex::detail {
boost::dll::shared_library lib;
internal::source_creator_t* fn{};

void operator()(source_bundle bundle, configuration const& config) const
void operator()(graph_registration_bundle bundle, configuration const& config) const
{
fn(bundle, config);
}
};

struct resource_plugin {
boost::dll::shared_library lib;
internal::resource_creator_t* fn{};

void operator()(resources_graph_proxy const& proxy, configuration const& config) const
{
fn(proxy, config);
}
};

struct driver_plugin {
boost::dll::shared_library lib;
internal::driver_shim_t* fn{};
Expand All @@ -56,12 +67,12 @@ namespace phlex::detail {
}
};

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<module_plugin> create_module;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<source_plugin> create_source;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<resource_plugin> create_resources;
std::optional<driver_plugin> create_driver;
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)

template <typename CreatorT>
std::pair<boost::dll::shared_library, CreatorT*> plugin_loader(std::string const& spec,
Expand Down Expand Up @@ -132,6 +143,24 @@ namespace phlex::detail {
creator(g.module_proxy(config), config);
}

void load_resource(framework_graph& g, std::string const& label, boost::json::object raw_config)
{
auto const adjusted_config = internal::adjust_config(label, std::move(raw_config));

auto const* cpp = adjusted_config.if_contains("cpp");
if (not cpp) {
throw std::runtime_error(
fmt::format("Missing 'cpp' parameter for {} -- only C++ resources are supported.", label));
}
auto const& spec = value_to<std::string>(*cpp);
auto [lib, fn] = plugin_loader<internal::resource_creator_t>(spec, "create_resources");
auto& creator = create_resources.emplace_back(resource_plugin{.lib = std::move(lib), .fn = fn});

configuration const config{adjusted_config};
auto const proxy = resources_graph_proxy{g.registration_bundle(config)};
creator(proxy, config);
}

void load_source(framework_graph& g, std::string const& label, boost::json::object raw_config)
{
auto const adjusted_config = internal::adjust_config(label, std::move(raw_config));
Expand All @@ -146,7 +175,7 @@ namespace phlex::detail {
// adjusted_config["module_label"] = label; // already set by adjust_config

configuration const config{adjusted_config};
creator(g.source_proxy(config), config);
creator(g.registration_bundle(config), config);
}

void load_driver(framework_graph& g, boost::json::object const& raw_config)
Expand Down
3 changes: 3 additions & 0 deletions phlex/app/load_module.hpp
Comment thread
knoepfel marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace phlex::detail {
RUN_PHLEX_EXPORT void load_module(framework_graph& g,
std::string const& label,
boost::json::object config);
RUN_PHLEX_EXPORT void load_resource(framework_graph& g,
std::string const& label,
boost::json::object config);
RUN_PHLEX_EXPORT void load_source(framework_graph& g,
std::string const& label,
boost::json::object config);
Expand Down
9 changes: 9 additions & 0 deletions phlex/app/run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ namespace phlex::detail {
{
auto g = framework_graph::without_driver(max_parallelism);

boost::json::object resource_configs;
if (configurations.contains("resources")) {
resource_configs = object_decorate_exception(configurations, "resources");
}

for (auto const& [key, value] : resource_configs) {
load_resource(g, key, value.as_object());
}

// It is allowed for users to not specify any modules
boost::json::object module_configs;
if (configurations.contains("modules")) {
Expand Down
2 changes: 1 addition & 1 deletion phlex/core/framework_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ namespace phlex::detail {
return {config, graph_, nodes_, registration_errors_, resources_};
}

source_bundle source_proxy(configuration const& config)
graph_registration_bundle registration_bundle(configuration const& config)
{
return {.config = config,
.graph = graph_,
Expand Down
11 changes: 11 additions & 0 deletions phlex/core/graph_proxy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ namespace phlex {
}

namespace phlex::detail {
struct graph_registration_bundle {
// Non-owning references to framework-owned resources; this is a short-lived struct.
// NOLINTBEGIN(cppcoreguidelines-avoid-const-or-ref-data-members)
configuration const& config;
tbb::flow::graph& graph;
node_catalog& nodes;
resource_catalog& resources;
std::vector<std::string>& registration_errors;
// NOLINTEND(cppcoreguidelines-avoid-const-or-ref-data-members)
};

// ==============================================================================
// Registering user functions

Expand Down
4 changes: 2 additions & 2 deletions phlex/detail/plugin_macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
// Source plugin entry-points cannot use extern "C" directly because the user-facing proxy types
// (providers_graph_proxy, source_graph_proxy) are C++ templates. Instead we:
// 1. Forward-declare the user's C++ implementation (takes the proxy by reference).
// 2. Define a thin extern "C" shim that accepts source_bundle by value (matching
// 2. Define a thin extern "C" shim that accepts graph_registration_bundle by value (matching
// source_creator_t exactly), constructs the appropriate proxy from the bundle,
// and calls the user's implementation.
// 3. Open the user's implementation definition for the body that follows the macro.
Expand All @@ -54,7 +54,7 @@

#define PHLEX_DETAIL_REGISTER_SOURCE_PLUGIN(token_type, func_name, dll_alias, ...) \
static PHLEX_DETAIL_SELECT_SOURCE_SIGNATURE(token_type, func_name, __VA_ARGS__); \
extern "C" void dll_alias(phlex::detail::source_bundle __phlex_bundle, \
extern "C" void dll_alias(phlex::detail::graph_registration_bundle __phlex_bundle, \
phlex::configuration const& __phlex_config) \
{ \
func_name(token_type<phlex::detail::void_tag>{__phlex_bundle}, __phlex_config); \
Expand Down
53 changes: 53 additions & 0 deletions phlex/resource.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef PHLEX_RESOURCE_HPP
#define PHLEX_RESOURCE_HPP

#include "phlex/core/graph_proxy.hpp"
#include "phlex/detail/plugin_macros.hpp"

#include <utility>

namespace phlex::detail {

/// @brief Proxy for registering resources.
///
/// Passed to @c PHLEX_REGISTER_RESOURCES plugin entry points. Only resource
/// registration is accessible. Users never construct this type directly.
class resources_graph_proxy {
public:
explicit resources_graph_proxy(graph_registration_bundle bundle) : resources_{bundle.resources}
{
}

template <typename Resource, typename... Args>
requires unlimited_resource_registration<Resource, Args...>
void add_unlimited_resource(Args&&... args) const
{
resources_.template add_unlimited<Resource>(std::forward<Args>(args)...);
}

template <typename Resource, typename... Args>
requires serialized_resource_registration<Resource, Args...>
void add_serialized_resource(Args&&... args) const
{
resources_.template add_serialized<Resource>(std::forward<Args>(args)...);
}

private:
resource_catalog& resources_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
};

namespace internal {
using resource_creator_t = void(resources_graph_proxy const&, configuration const&);

// The plugin mechanism requires a template, but resources_graph_proxy doesn't need to be one.
// The following template alias is the workaround.
template <std::same_as<void_tag> T>
using resources_graph_proxy_shim = resources_graph_proxy;
}
}

#define PHLEX_REGISTER_RESOURCES(...) \
PHLEX_DETAIL_REGISTER_PLUGIN( \
phlex::detail::internal::resources_graph_proxy_shim, create, create_resources, __VA_ARGS__)

#endif // PHLEX_RESOURCE_HPP
18 changes: 3 additions & 15 deletions phlex/source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,6 @@
#include <utility>

namespace phlex::detail {

struct source_bundle {
// Non-owning references to framework-owned resources; source_bundle is a short-lived struct.
// NOLINTBEGIN(cppcoreguidelines-avoid-const-or-ref-data-members)
configuration const& config;
tbb::flow::graph& graph;
node_catalog& nodes;
resource_catalog& resources;
std::vector<std::string>& registration_errors;
// NOLINTEND(cppcoreguidelines-avoid-const-or-ref-data-members)
};

/// @brief Proxy for registering explicit provider nodes.
///
/// Passed to @c PHLEX_REGISTER_PROVIDERS plugin entry points. Only provide
Expand All @@ -31,7 +19,7 @@ namespace phlex::detail {
using base = graph_proxy<T>;

public:
providers_graph_proxy(source_bundle bundle) :
providers_graph_proxy(graph_registration_bundle bundle) :
base{bundle.config, bundle.graph, bundle.nodes, bundle.registration_errors, bundle.resources}
{
}
Expand All @@ -58,7 +46,7 @@ namespace phlex::detail {
using base = graph_proxy<T>;

public:
source_graph_proxy(source_bundle bundle) :
source_graph_proxy(graph_registration_bundle bundle) :
base{bundle.config, bundle.graph, bundle.nodes, bundle.registration_errors, bundle.resources}
{
}
Expand All @@ -68,7 +56,7 @@ namespace phlex::detail {
};

namespace internal {
using source_creator_t = void(source_bundle, configuration const&);
using source_creator_t = void(graph_registration_bundle, configuration const&);
}
}

Expand Down
11 changes: 11 additions & 0 deletions test/adjust_config_test.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "phlex/app/load_module.hpp"
#include "phlex/core/framework_graph.hpp"

#include "catch2/catch_test_macros.hpp"
#include "catch2/matchers/catch_matchers_string.hpp"
Expand Down Expand Up @@ -59,3 +60,13 @@ TEST_CASE("Both py and cpp specified, cpp as string", "[config]")
CHECK_THROWS_WITH(adjust_config("malformed3", std::move(obj)),
Catch::Matchers::ContainsSubstring(err_msg));
}

TEST_CASE("Loading resources requires a cpp parameter", "[config]")
{
auto graph = phlex::detail::framework_graph::without_driver();

CHECK_THROWS_WITH(
phlex::detail::load_resource(graph, "my_resource", {}),
Catch::Matchers::ContainsSubstring(
"Missing 'cpp' parameter for my_resource -- only C++ resources are supported."));
}
19 changes: 19 additions & 0 deletions test/plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ target_link_libraries(ij_source PRIVATE phlex::source)
add_library(output MODULE output.cpp)
target_link_libraries(output PRIVATE phlex::module)

add_library(register_resources_for_testing MODULE register_resources_for_testing.cpp)
target_link_libraries(register_resources_for_testing PRIVATE phlex::resource)

add_library(verify_resources MODULE verify_resources.cpp)
target_link_libraries(verify_resources PRIVATE phlex::module)

cet_test(
job:add
HANDBUILT
Expand All @@ -19,3 +25,16 @@ cet_test(
ENVIRONMENT
"PHLEX_PLUGIN_PATH=${PROJECT_BINARY_DIR}/${phlex_LIBRARY_DIR}"
)

cet_test(
job:resources
HANDBUILT
TEST_EXEC
phlex::phlex
TEST_ARGS
-c
${CMAKE_CURRENT_SOURCE_DIR}/test_resources.jsonnet
TEST_PROPERTIES
ENVIRONMENT
"PHLEX_PLUGIN_PATH=${PROJECT_BINARY_DIR}/${phlex_LIBRARY_DIR}"
)
26 changes: 26 additions & 0 deletions test/plugins/register_resources_for_testing.cpp
Comment thread
knoepfel marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "phlex/configuration.hpp"
#include "phlex/resource.hpp"
#include "test/plugins/resources_for_testing.hpp"

using namespace phlex;
using namespace test::plugins;

namespace {
using proxy = detail::resources_graph_proxy;

template <typename T>
concept exposes_observe =
requires(T const& resource_proxy) { resource_proxy.observe("invalid", [](int) {}); };

static_assert(requires(proxy const& r) {
r.template add_unlimited_resource<configured_resource>(1);
r.template add_serialized_resource<serialized_resource>();
});
static_assert(not exposes_observe<proxy>);
}

PHLEX_REGISTER_RESOURCES(r, config)
{
r.add_unlimited_resource<configured_resource>(config.get<int>("value"));
r.add_serialized_resource<serialized_resource>();
}
16 changes: 16 additions & 0 deletions test/plugins/resources_for_testing.hpp
Comment thread
knoepfel marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef TEST_PLUGINS_RESOURCES_FOR_TESTING_HPP
#define TEST_PLUGINS_RESOURCES_FOR_TESTING_HPP

namespace test::plugins {
struct configured_resource {
explicit configured_resource(int value) : value{value} {}

int value;
};

struct serialized_resource {
using token_type = serialized_resource const*;
};
}

#endif // TEST_PLUGINS_RESOURCES_FOR_TESTING_HPP
24 changes: 24 additions & 0 deletions test/plugins/test_resources.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
resources: {
resources_for_testing: {
cpp: 'register_resources_for_testing',
value: 42,
},
},
driver: {
cpp: 'generate_layers',
layers: {
event: { parent: 'job', total: 10, starting_number: 1 },
},
},
sources: {
provider: {
cpp: 'ij_source',
},
},
modules: {
verify_resources: {
cpp: 'verify_resources',
},
},
}
Loading
Loading