Skip to content

Commit f696aa5

Browse files
authored
Allow drivers to access configured sources (#658)
* Support updating the hierarchy * Adjust framework_graph construction to allow deferred setting of the driver * Allow drivers to access sources * Rename g.source<T> to g.add_source<T> * Adjustments to driver(...) overloads
1 parent 5ffc36a commit f696aa5

39 files changed

Lines changed: 734 additions & 254 deletions

form/form_source.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ PHLEX_REGISTER_SOURCE(s, config)
191191
}
192192

193193
// Register the source object with Phlex
194-
s.source<FormInputSource>(
194+
s.add_source<FormInputSource>(
195195
module_label, input_cfg, tech_cfg, actual_creator, advertised_creator, products);
196196

197197
std::cout << "FORM input source registered successfully\n";

phlex/app/load_module.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,17 @@ namespace phlex::experimental {
113113
creator(g.source_proxy(config), config);
114114
}
115115

116-
driver_bundle load_driver(boost::json::object const& raw_config)
116+
void load_driver(framework_graph& g, boost::json::object const& raw_config)
117117
{
118118
configuration const config{raw_config};
119119
auto const& spec = config.get<std::string>("cpp");
120+
auto const required_sources = config.get<std::vector<std::string>>("uses_sources", {});
120121
// False positive: clang-analyzer cannot trace ownership through Boost's is_any_of<char>
121122
// internal reference counting in classification.hpp.
122123
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks,clang-analyzer-cplusplus.NewDelete)
123124
create_driver = plugin_loader<detail::driver_shim_t>(spec, "create_driver");
124125
driver_bundle result;
125-
create_driver(driver_proxy{}, config, &result);
126-
return result;
126+
create_driver(g.driver_proxy(required_sources), config, &result);
127+
g.add_driver(result);
127128
}
128129
}

phlex/app/load_module.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace phlex::experimental {
2222
RUN_PHLEX_EXPORT void load_source(framework_graph& g,
2323
std::string const& label,
2424
boost::json::object config);
25-
RUN_PHLEX_EXPORT driver_bundle load_driver(boost::json::object const& config);
25+
RUN_PHLEX_EXPORT void load_driver(framework_graph& g, boost::json::object const& config);
2626
}
2727

2828
#endif // PHLEX_APP_LOAD_MODULE_HPP

phlex/app/run.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ namespace {
1717
namespace phlex::experimental {
1818
void run(boost::json::object const& configurations, int const max_parallelism)
1919
{
20-
auto const driver_config = object_decorate_exception(configurations, "driver");
21-
framework_graph g{load_driver(driver_config), max_parallelism};
20+
auto g = framework_graph::without_driver(max_parallelism);
2221

2322
// It is allowed for users to not specify any modules
2423
boost::json::object module_configs;
@@ -38,6 +37,10 @@ namespace phlex::experimental {
3837
for (auto const& [key, value] : source_configs) {
3938
load_source(g, key, value.as_object());
4039
}
40+
41+
auto const driver_config = object_decorate_exception(configurations, "driver");
42+
load_driver(g, driver_config);
43+
4144
g.execute();
4245
}
4346
}

phlex/core/framework_graph.cpp

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,23 @@
1515
#include <iostream>
1616

1717
namespace phlex::experimental {
18-
framework_graph::framework_graph(int const max_parallelism) :
19-
framework_graph{[](framework_driver& driver) { driver.yield(data_cell_index::job()); },
20-
max_parallelism}
18+
framework_graph framework_graph::with_default_driver(int const max_parallelism)
2119
{
20+
return framework_graph{driver_mode::default_driver, max_parallelism};
2221
}
2322

24-
framework_graph::framework_graph(detail::next_index_t next_index, int const max_parallelism) :
25-
framework_graph{driver_bundle{std::move(next_index), {}}, max_parallelism}
23+
framework_graph framework_graph::without_driver(int const max_parallelism)
2624
{
25+
return framework_graph{driver_mode::deferred_driver, max_parallelism};
2726
}
2827

29-
framework_graph::framework_graph(driver_bundle bundle, int const max_parallelism) :
28+
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
29+
framework_graph::framework_graph(driver_mode const mode, int const max_parallelism) :
3030
parallelism_limit_{static_cast<std::size_t>(max_parallelism)},
31-
fixed_hierarchy_{std::move(bundle.hierarchy)},
32-
driver_{std::move(bundle.driver)},
3331
src_{graph_,
3432
[this](tbb::flow_control& fc) mutable -> ready_flushes_then_emit {
35-
if (auto item = driver_()) {
33+
assert(driver_);
34+
if (auto item = (*driver_)()) {
3635
return {.ready_flushes = cell_tracker_.report_and_evict_ready_flushes(*item),
3736
.index_to_emit = *item};
3837
}
@@ -51,12 +50,33 @@ namespace phlex::experimental {
5150
[this](data_cell_index_ptr const& index) -> tbb::flow::continue_msg {
5251
hierarchy_.increment_count(index);
5352
return {};
54-
}}
53+
}},
54+
driver_mode_{mode}
5555
{
56+
if (driver_mode_ == driver_mode::default_driver) {
57+
driver_.emplace([](framework_driver& driver) { driver.yield(data_cell_index::job()); });
58+
}
59+
5660
spdlog::cfg::load_env_levels();
5761
spdlog::info("Number of worker threads: {}", max_allowed_parallelism::active_value());
5862
}
5963

64+
void framework_graph::add_driver(driver_bundle bundle)
65+
{
66+
if (driver_mode_ != driver_mode::deferred_driver) {
67+
throw std::runtime_error(
68+
"Cannot configure framework_graph with a driver when not in deferred mode.");
69+
}
70+
if (driver_) {
71+
throw std::runtime_error("Driver has already been configured for framework_graph.");
72+
}
73+
if (!bundle.driver) {
74+
throw std::runtime_error("Cannot configure framework_graph with an empty driver.");
75+
}
76+
fixed_hierarchy_ = std::move(bundle.hierarchy);
77+
driver_.emplace(std::move(bundle.driver));
78+
}
79+
6080
framework_graph::~framework_graph()
6181
{
6282
if (shutdown_on_error_) {
@@ -79,19 +99,26 @@ namespace phlex::experimental {
7999
}
80100

81101
void framework_graph::execute()
82-
try {
83-
finalize();
84-
run();
85-
} catch (std::exception const& e) {
86-
driver_.stop();
87-
spdlog::error(e.what());
88-
shutdown_on_error_ = true;
89-
throw;
90-
} catch (...) {
91-
driver_.stop();
92-
spdlog::error("Unknown exception during graph execution");
93-
shutdown_on_error_ = true;
94-
throw;
102+
{
103+
if (!driver_) {
104+
throw std::runtime_error("No driver configured for framework_graph.");
105+
}
106+
107+
try {
108+
finalize();
109+
run();
110+
} catch (std::exception const& e) {
111+
driver_->stop();
112+
113+
spdlog::error(e.what());
114+
shutdown_on_error_ = true;
115+
throw;
116+
} catch (...) {
117+
driver_->stop();
118+
spdlog::error("Unknown exception during graph execution");
119+
shutdown_on_error_ = true;
120+
throw;
121+
}
95122
}
96123

97124
void framework_graph::run()

phlex/core/framework_graph.hpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <functional>
2727
#include <map>
2828
#include <memory>
29+
#include <optional>
2930
#include <string>
3031
#include <tuple>
3132
#include <utility>
@@ -38,17 +39,28 @@ namespace phlex {
3839
namespace phlex::experimental {
3940
class PHLEX_CORE_EXPORT framework_graph {
4041
public:
41-
explicit framework_graph(int max_parallelism = oneapi::tbb::info::default_concurrency());
42-
explicit framework_graph(detail::next_index_t next_index,
43-
int max_parallelism = oneapi::tbb::info::default_concurrency());
44-
explicit framework_graph(driver_bundle bundle,
45-
int max_parallelism = oneapi::tbb::info::default_concurrency());
42+
[[nodiscard]] static framework_graph with_default_driver(
43+
int max_parallelism = oneapi::tbb::info::default_concurrency());
44+
[[nodiscard]] static framework_graph without_driver(
45+
int max_parallelism = oneapi::tbb::info::default_concurrency());
46+
4647
~framework_graph();
4748
framework_graph(framework_graph const&) = delete;
4849
framework_graph& operator=(framework_graph const&) = delete;
4950
framework_graph(framework_graph&&) = delete;
5051
framework_graph& operator=(framework_graph&&) = delete;
5152

53+
void add_driver(driver_bundle bundle);
54+
55+
template <typename Generator>
56+
requires requires(std::shared_ptr<Generator> generator, std::vector<source const*> sources) {
57+
{ experimental::driver_proxy{sources}.driver(generator) } -> std::same_as<driver_bundle>;
58+
}
59+
void add_driver(std::shared_ptr<Generator> generator)
60+
{
61+
add_driver(driver_proxy().driver(std::move(generator)));
62+
}
63+
5264
void execute();
5365

5466
std::size_t seen_cell_count(std::string const& layer_name, bool missing_ok = false) const;
@@ -64,6 +76,11 @@ namespace phlex::experimental {
6476
return {config, graph_, nodes_, registration_errors_};
6577
}
6678

79+
experimental::driver_proxy driver_proxy(std::vector<std::string> strings = {})
80+
{
81+
return experimental::driver_proxy(nodes_.sources_for(strings));
82+
}
83+
6784
// Framework function registrations
6885

6986
// N.B. declare_output() is not directly accessible through framework_graph. Is this
@@ -115,9 +132,9 @@ namespace phlex::experimental {
115132
}
116133

117134
template <std::derived_from<source> Source, typename... Args>
118-
void source(std::string name, Args&&... args)
135+
void add_source(std::string name, Args&&... args)
119136
{
120-
return make_glue().template source<Source>(std::move(name), std::forward<Args>(args)...);
137+
return make_glue().template add_source<Source>(std::move(name), std::forward<Args>(args)...);
121138
}
122139

123140
template <typename T, typename... Args>
@@ -170,6 +187,9 @@ namespace phlex::experimental {
170187
void finalize_router(index_router::provider_input_ports_t provider_input_ports,
171188
std::map<std::string, named_index_ports> multilayer_join_index_ports);
172189

190+
enum class driver_mode { default_driver, deferred_driver };
191+
explicit framework_graph(driver_mode mode, int max_parallelism);
192+
173193
resource_usage graph_resource_usage_{};
174194
max_allowed_parallelism parallelism_limit_;
175195
fixed_hierarchy fixed_hierarchy_;
@@ -178,7 +198,7 @@ namespace phlex::experimental {
178198
std::map<std::string, filter> filters_{};
179199
// The graph_ object uses the filters_, nodes_, and hierarchy_ objects implicitly.
180200
tbb::flow::graph graph_{};
181-
framework_driver driver_;
201+
std::optional<framework_driver> driver_{};
182202
std::vector<std::string> registration_errors_{};
183203
data_cell_tracker cell_tracker_{};
184204
tbb::flow::input_node<ready_flushes_then_emit> src_;
@@ -187,6 +207,7 @@ namespace phlex::experimental {
187207
index_receiver_;
188208
tbb::flow::function_node<data_cell_index_ptr, tbb::flow::continue_msg, tbb::flow::lightweight>
189209
hierarchy_node_;
210+
driver_mode driver_mode_{driver_mode::default_driver};
190211
bool shutdown_on_error_{false};
191212
};
192213
}

phlex/core/glue.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ namespace phlex::experimental {
152152
}
153153

154154
template <std::derived_from<source> Source, typename... Args>
155-
void source(std::string name, Args&&... args)
155+
void add_source(std::string name, Args&&... args)
156156
{
157157
auto [_, inserted] =
158158
nodes_.sources.try_emplace(name, std::make_unique<Source>(std::forward<Args>(args)...));

phlex/core/graph_proxy.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ namespace phlex::experimental {
109109

110110
/// @brief Registers a source (used by the framework to create provider nodes)
111111
template <std::derived_from<source> Source, typename... Args>
112-
void source(std::string name, Args&&... args)
112+
void add_source(std::string name, Args&&... args)
113113
requires(not is_bound_object<T>)
114114
{
115115
// The bound object is created when invoking source<Source>(...), so we explicitly indicate that
116116
// no bound object should be used in the create_glue(...) call.
117-
return create_glue(false).template source<Source>(std::move(name),
118-
std::forward<Args>(args)...);
117+
return create_glue(false).template add_source<Source>(std::move(name),
118+
std::forward<Args>(args)...);
119119
}
120120

121121
/// @brief Registers an output node.

phlex/core/node_catalog.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#include "phlex/core/node_catalog.hpp"
22

3+
#include "fmt/format.h"
4+
35
#include <string>
6+
#include <vector>
47

58
using namespace std::string_literals;
69

@@ -53,4 +56,18 @@ namespace phlex::experimental {
5356
{
5457
return producer_catalog{transforms, folds, unfolds};
5558
}
59+
60+
source_vector node_catalog::sources_for(std::vector<std::string> const& keys) const
61+
{
62+
source_vector result;
63+
result.reserve(keys.size());
64+
for (auto const& key : keys) {
65+
if (auto src = sources.get(key)) {
66+
result.push_back(src);
67+
} else {
68+
throw std::runtime_error(fmt::format("Unknown source with name: {}", key));
69+
}
70+
}
71+
return result;
72+
}
5673
}

phlex/core/node_catalog.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ namespace phlex::experimental {
2828
return registrar{ptr_map_for<Ptr>(), errors};
2929
}
3030

31+
source_vector sources_for(std::vector<std::string> const& keys) const;
32+
3133
std::size_t execution_count(std::string const& node_name) const;
3234
std::vector<products_consumer*> consumers() const;
3335
producer_catalog producers() const;

0 commit comments

Comments
 (0)