0

I'm trying to come up with a way to define a flow graph (think TBB) defined at runtime. Currently, we use TBB to define the nodes and the edges between the nodes at compile time. This is sort of annoying because we have people who want to add processing steps and modify the processing chain without recompiling the whole application or really having to know anything about the application beyond how to add processing kernels. In an ideal world I would have some sort of plugin framework using dlls. We already have the software architected so that each node in TBB represents a processing step so it's pretty easy to add stuff if you're willing to recompile.

As a first step, I was trying to come up with a way to define a TBB flow graph in YAML but it was a massive rabbit hole. Does anyone know if something like this exists before I go all in on implementing this from scratch? It will be a fun project but no point in duplicating work.

dHubley
  • 25
  • 4

1 Answers1

1

I am not sure if anything like this exists in a TBB companion library but it is definitely doable to implement a small subset of the functionalities of Flow Graph configurable at runtime.

If the data that transit through your graph have a well defined type, aka your nodes are basically function_node<T, T> things are manageable. If the Graph transforms data from one type to another it gets more complicated -one solution would be to use a variant of these types and handle the possibly incompatible types at runtime. That really depends on the level of flexibility required.

With:

$ cat nodes.txt
# type concurrency params...
multiply unlimited 2 
affine serial 5 -3

and

$ cat edges.txt
# src dst
0 1 
1 2

where index 0 is a source node, here is a scaffold of how I would implement it:

using data_t = double;
using node_t = function_node<data_t , data_t >;

graph g;
std::vector<node_t> nodes;

auto node_factory = [&g](std::string type, std::string concurrency, std::string params) -> node_t {
    // Implement a dynamic factory of nodes
};

// Add source node first
nodes.push_back(flow::input_node<data_t>(g,
    [&]( oneapi::tbb::flow_control &fc ) -> data_t { /*...*/ });

// Parse the node description file and populate the node vector using the factory
for (auto&& n : nodes)
    nodes.push_back(node_factory(n.type, n.concurrency, n.params));

// Parse the edge description file and call make_edge accordingly
for (auto&& e : edges)
    flow::make_edge(nodes[e.src], nodes[e.dst]);

// Run the graph
nodes[0].activate();
g.wait_for_all();
Samuel
  • 131
  • 1
  • 5