Hedgehog  3.1.0
A library to generate hybrid pipeline workflow systems
Loading...
Searching...
No Matches
hh::Graph< Separator, AllTypes > Class Template Reference

Hedgehog graph abstraction. More...

#include "graph.h"

Inheritance diagram for hh::Graph< Separator, AllTypes >:
Inheritance graph
Collaboration diagram for hh::Graph< Separator, AllTypes >:
Collaboration graph

Public Member Functions

 Graph (std::string const &name="Graph", std::unique_ptr< Scheduler > scheduler=std::make_unique< DefaultScheduler >())
 Default graph constructor, construct a graph with the name "Graph" and with a default scheduler.
 
 ~Graph () override=default
 Default graph destructor.
 
template<tool::CompatibleInputNode< typename core::GIM< Separator, AllTypes... >::inputs_t > InputNode_t>
void inputs (std::shared_ptr< InputNode_t > inputNode)
 Set an input node and connect the node to the graph's inputs for all common types.
 
template<class InputDataType , tool::CompatibleInputNodeForAType< InputDataType, typename core::GIM< Separator, AllTypes... >::inputs_t > InputNode_t>
void input (std::shared_ptr< InputNode_t > inputNode)
 Set an input node and connect the node to the graph's input InputDataType.
 
template<tool::CompatibleOutputNode< typename core::GOM< Separator, AllTypes... >::outputs_t > OutputNode_t>
void outputs (std::shared_ptr< OutputNode_t > outputNode)
 Set an output node and connect the node to the graph's outputs for all common types.
 
template<class OutputType , tool::CompatibleOutputNodeForAType< OutputType, typename core::GOM< Separator, AllTypes... >::outputs_t > OutputNode_t>
void output (std::shared_ptr< OutputNode_t > outputNode)
 Set an output node and connect the node to the graph's output OutputDataType.
 
template<tool::SenderNode SenderNode_t, tool::ReceiverNode ReceiverNode_t>
void edges (std::shared_ptr< SenderNode_t > sender, std::shared_ptr< ReceiverNode_t > receiver)
 Create an edge between two nodes for all common types.
 
template<class CommonType , tool::SenderNodeForAType< CommonType > SenderNode_t, tool::ReceiverNodeForAType< CommonType > ReceiverNode_t>
void edge (std::shared_ptr< SenderNode_t > sender, std::shared_ptr< ReceiverNode_t > receiver)
 Create an edge between two nodes for a specific type.
 
void executeGraph (bool waitForInitialization=false)
 Execute the graph.
 
void finishPushingData ()
 Indicate to the graph that no more input data are pushed to the graph.
 
template<tool::MatchInputTypeConcept< tool::Inputs< Separator, AllTypes... > > CompatibleInputType_t>
void pushData (std::shared_ptr< CompatibleInputType_t > data)
 Push data into the graph.
 
void waitForTermination ()
 Wait for the graph to terminate.
 
auto getBlockingResult ()
 Get result data from the graph.
 
void createDotFile (std::filesystem::path const &dotFilePath, ColorScheme colorScheme=ColorScheme::NONE, StructureOptions structureOptions=StructureOptions::NONE, DebugOptions debugOption=DebugOptions::NONE, std::unique_ptr< ColorPicker > colorPicker=std::make_unique< JetColor >(), bool verbose=false)
 Create a dot file representing a snapshot of the state of the graph at the moment of the call, the graph is saved into the file dotFilePath.
 
void deviceId (int deviceId)
 Set the device id (GPU ID) for all the nodes in a graph.
 
void cleanGraph ()
 Clean the graph.
 
- Public Member Functions inherited from hh::behavior::Node
 Node (std::shared_ptr< hh::core::abstraction::NodeAbstraction > core)
 Constructor's node.
 
virtual ~Node ()=default
 Default destructor.
 
std::shared_ptr< hh::core::abstraction::NodeAbstraction > const & core () const
 Core accessor.
 
std::string name () const
 Node's name accessor.
 

Private Attributes

std::shared_ptr< core::CoreGraph< Separator, AllTypes... > > const coreGraph_ = nullptr
 Core of the graph.
 
std::unique_ptr< std::set< std::shared_ptr< Node > > > nodes_ = nullptr
 Set of nodes given by the end user.
 

Detailed Description

template<size_t Separator, class ... AllTypes>
class hh::Graph< Separator, AllTypes >

Hedgehog graph abstraction.

The graph in the Hedgehog library allows the user to create a dataflow. The graph regroups a set of nodes representing parts of the computation. The most important nodes are the tasks (for heavy computation), the state managers (to manage the local state of the computation) and the graph themselves (nested computation).

If a node is set as input of the graph (Graph::input / Graph::inputs), the data sent to the graph are transmitted to the input nodes. The output nodes (set with Graph::output / Graph::outputs) produce the output data of the graph. Between the input and the output nodes, the nodes need to be connected via edges(Graph::edge / Graph::edges).

A graph can be duplicated with ah hh::AbstractExecutionPipeline. Useful for mapping data across multiple devices (such as GPUs).

The difference between the singular and plural method (Graph::input / Graph::inputs, Graph::output / Graph::outputs, Graph::edge / Graph::edges) is/are the type[s] used for the connection: if it is plural the connection is made for all possible types, if it is singular the connection is only made for the user specified type.

The sequence of operations to use a graph are:

  • Instantiate a graph [See example]
  • Populate the graph [See example]
  • Run the graph (Graph::executeGraph)
  • Push data into the graph (Graph::pushData)
  • Indicate that no more data will be pushed (Graph::finishPushingData)
  • Gather output data with Graph::getBlockingResult can be put in a while loop, the function returns nullptr when the graph is terminated (with Graph::finishPushingData) and all data have been processed.
  • Wait for the graph to fully terminate (Graph::waitForTermination)
    // Instantiate a graph and its nodes
    auto g = std::make_shared<hh::Graph<3, int, float, double, int, float, double>>();
    auto innerInputInt = std::make_shared<IntFloatDoubleTask>();
    auto innerTaskFloat = std::make_shared<IntFloatDoubleTask>();
    auto innerOutput = std::make_shared<IntFloatDoubleTask>();
    auto innerSM = std::make_shared<hh::StateManager<1, int, int>>(std::make_shared<IntState>());
    auto innerGraph = std::make_shared<IntFloatDoubleGraph>();
    // Create a graph
    g->input<int>(innerInputInt);
    g->input<float>(innerTaskFloat);
    g->inputs(innerSM);
    g->inputs(innerGraph);
    g->edges(innerInputInt, innerOutput);
    g->edges(innerSM, innerOutput);
    g->edges(innerTaskFloat, innerOutput);
    g->outputs(innerOutput);
    g->outputs(innerGraph);
    g->executeGraph(); // Execute the graph
    // Push different types of data
    for (int i = 0; i < 2000; ++i) {
    g->pushData(std::make_shared<int>(i));
    g->pushData(std::make_shared<float>(i));
    g->pushData(std::make_shared<double>(i));
    }
    // Indicate that no other data will be pushed (trigger termination of the graph)
    g->finishPushingData();
    // Get the output data
    while (auto variant = g->getBlockingResult()) {
    std::visit(hh::ResultVisitor{
    [](std::shared_ptr<int> &val) { /*Do something with an int*/ },
    [](std::shared_ptr<float> &val) { /*Do something else with a float*/ },
    [](std::shared_ptr<double> &val) { /*Do something else again with a double*/ }
    }, *variant);
    }
    // Wait for the graph to terminate
    g->waitForTermination();
    Visitor used to explore Hedgehog graph variant result.
    The default scheduling method for a graph is to launch all the node's threads and let the OS manages the threads.
    Attention
    The conformity rules are: 1) for the input nodes, the node and the graph should share at least one input type, 2) for the output nodes, the node and the graph should share at least one output type and 3) between two nodes an edge can only be drawn for [a] common type[s].
    If the process wants to push a certain amount of data / get the output and start with new input data, the Graph::pushData and Graph::getBlockingResult can be alternated without the while loop because the graph won't terminate. This technique can only be used if the number of output can be deduced in advance by the end user. Once all processing is complete, then the user must indicate they are done with Graph::finishPushingData, otherwise the graph will deadlock and never terminate. The Graph::cleanGraph method can be used to "clean" the graph nodes, and reset the user nodes attributes between computations.
    Template Parameters
    SeparatorSeparator position between input types and output types
    AllTypesList of input and output types

Definition at line 134 of file graph.h.

Constructor & Destructor Documentation

◆ Graph()

template<size_t Separator, class ... AllTypes>
hh::Graph< Separator, AllTypes >::Graph ( std::string const &  name = "Graph< Separator, AllTypes >",
std::unique_ptr< Scheduler scheduler = std::make_unique<DefaultScheduler>() 
)
inlineexplicit

Default graph constructor, construct a graph with the name "Graph" and with a default scheduler.

Parameters
nameName of the graph to construct
schedulerScheduler used by the graph (should inherit from hh::Scheduler)
Exceptions
std::runtime_errorif the core is not valid, should derives from CoreGraph

Definition at line 156 of file graph.h.

Here is the call graph for this function:

◆ ~Graph()

template<size_t Separator, class ... AllTypes>
hh::Graph< Separator, AllTypes >::~Graph ( )
overridedefault

Default graph destructor.

Member Function Documentation

◆ cleanGraph()

template<size_t Separator, class ... AllTypes>
void hh::Graph< Separator, AllTypes >::cleanGraph ( )
inline

Clean the graph.

Call in sequence the clean method in all internal nodes. May be use to reset the attributes of user nodes between computations.

Definition at line 345 of file graph.h.

◆ createDotFile()

template<size_t Separator, class ... AllTypes>
void hh::Graph< Separator, AllTypes >::createDotFile ( std::filesystem::path const &  dotFilePath,
ColorScheme  colorScheme = ColorScheme::NONE,
StructureOptions  structureOptions = StructureOptions::NONE,
DebugOptions  debugOption = DebugOptions::NONE,
std::unique_ptr< ColorPicker colorPicker = std::make_unique<JetColor>(),
bool  verbose = false 
)
inline

Create a dot file representing a snapshot of the state of the graph at the moment of the call, the graph is saved into the file dotFilePath.

Parameters
dotFilePathPath where the file is stored.
colorSchemeColor scheme used to color the tasks, either to show difference in execution or in waiting times, or nothing. The chosen color depends on the colorPicker.
structureOptionsShow how the graph is represented, with or without input queue size, with or without all task groups.
debugOptionAdd debug information on the dot graph.
colorPickerColor scheme used to generate the dotfile, JetColor by default.
verboseEnable verbose mode: report when dot files are created or overwritten to standard out, default false.

Definition at line 324 of file graph.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ deviceId()

template<size_t Separator, class ... AllTypes>
void hh::Graph< Separator, AllTypes >::deviceId ( int  deviceId)
inline

Set the device id (GPU ID) for all the nodes in a graph.

Parameters
deviceIdDevice Id to set

Definition at line 340 of file graph.h.

◆ edge()

template<size_t Separator, class ... AllTypes>
template<class CommonType , tool::SenderNodeForAType< CommonType > SenderNode_t, tool::ReceiverNodeForAType< CommonType > ReceiverNode_t>
void hh::Graph< Separator, AllTypes >::edge ( std::shared_ptr< SenderNode_t >  sender,
std::shared_ptr< ReceiverNode_t >  receiver 
)
inline

Create an edge between two nodes for a specific type.

Validate the sender and receiver node and if valid, create an edge for the CommonType type

Template Parameters
SenderNode_tType of the sender node
ReceiverNode_tType of the receiver node
Parameters
senderSender node
receiverReceiver node

Definition at line 259 of file graph.h.

◆ edges()

template<size_t Separator, class ... AllTypes>
template<tool::SenderNode SenderNode_t, tool::ReceiverNode ReceiverNode_t>
void hh::Graph< Separator, AllTypes >::edges ( std::shared_ptr< SenderNode_t >  sender,
std::shared_ptr< ReceiverNode_t >  receiver 
)
inline

Create an edge between two nodes for all common types.

Validate the sender and receiver node and if valid, create an edge for all common types between the sender output types and the receiver input types

Template Parameters
SenderNode_tType of the sender node
ReceiverNode_tType of the receiver node
Parameters
senderSender node
receiverReceiver node

Definition at line 234 of file graph.h.

◆ executeGraph()

template<size_t Separator, class ... AllTypes>
void hh::Graph< Separator, AllTypes >::executeGraph ( bool  waitForInitialization = false)
inline

Execute the graph.

Duplicate the nodes in a group and use the scheduler to associate threads to the nodes

Parameters
waitForInitializationWait for internal nodes to be initialized flags [default = false]

Definition at line 275 of file graph.h.

◆ finishPushingData()

template<size_t Separator, class ... AllTypes>
void hh::Graph< Separator, AllTypes >::finishPushingData ( )
inline

Indicate to the graph that no more input data are pushed to the graph.

Trigger the termination of the graph, each nodes terminates in a cascaded when (by default) no predecessor node is connected to the node and the input node queues are empty.

Definition at line 280 of file graph.h.

◆ getBlockingResult()

template<size_t Separator, class ... AllTypes>
auto hh::Graph< Separator, AllTypes >::getBlockingResult ( )
inline

Get result data from the graph.

Get result from the graph while blocking the main thread. The results are presented under the form of

std::shared_ptr<std::variant<std::shared_ptr<Output1>, std::shared_ptr<Output2>, std::shared_ptr<Output3>>>

If the output type is known in advance one can use

std::get<std::shared_ptr<KnownType>>(*result)

If multiple types are possible the following code can be used:

std::visit(hh::ResultVisitor{
[](std::shared_ptr<Output1> &val) { /*Do something with an Output1*/ },
[](std::shared_ptr<Output2> &val) { /*Do something else with a Output2*/ },
[](std::shared_ptr<Output3> &val) { /*Do something else again with a Output3*/ }
}, *result);
Returns
A result of the graph

Definition at line 311 of file graph.h.

◆ input()

template<size_t Separator, class ... AllTypes>
template<class InputDataType , tool::CompatibleInputNodeForAType< InputDataType, typename core::GIM< Separator, AllTypes... >::inputs_t > InputNode_t>
void hh::Graph< Separator, AllTypes >::input ( std::shared_ptr< InputNode_t >  inputNode)
inline

Set an input node and connect the node to the graph's input InputDataType.

Check if the input node is a valid object, and then connect it to the graph input for the InputDataType type.

Template Parameters
InputDataTypeInput type used for the connection between the node and the graph
InputNode_tType of the input node
Parameters
inputNodeInput node to connect

Definition at line 189 of file graph.h.

◆ inputs()

template<size_t Separator, class ... AllTypes>
template<tool::CompatibleInputNode< typename core::GIM< Separator, AllTypes... >::inputs_t > InputNode_t>
void hh::Graph< Separator, AllTypes >::inputs ( std::shared_ptr< InputNode_t >  inputNode)
inline

Set an input node and connect the node to the graph's inputs for all common types.

Check if the input node is a valid object, and then connect it to the graph for all common types.

Template Parameters
InputNode_tType of the input node
Parameters
inputNodeInput node to connect

Definition at line 173 of file graph.h.

◆ output()

template<size_t Separator, class ... AllTypes>
template<class OutputType , tool::CompatibleOutputNodeForAType< OutputType, typename core::GOM< Separator, AllTypes... >::outputs_t > OutputNode_t>
void hh::Graph< Separator, AllTypes >::output ( std::shared_ptr< OutputNode_t >  outputNode)
inline

Set an output node and connect the node to the graph's output OutputDataType.

Check if the output node is a valid object, and then connect it to the graph output for the OutputDataType type.

Template Parameters
OutputDataTypeOutput type used for the connection between the node and the graph
OutputNode_tType of the output node
Parameters
outputNodeOutput node to connect

Definition at line 218 of file graph.h.

◆ outputs()

template<size_t Separator, class ... AllTypes>
template<tool::CompatibleOutputNode< typename core::GOM< Separator, AllTypes... >::outputs_t > OutputNode_t>
void hh::Graph< Separator, AllTypes >::outputs ( std::shared_ptr< OutputNode_t >  outputNode)
inline

Set an output node and connect the node to the graph's outputs for all common types.

Check if the output node is a valid object, and then connect it to the graph output for all common types.

Template Parameters
OutputNode_tType of the output node
Parameters
outputNodeOutput node to connect

Definition at line 202 of file graph.h.

◆ pushData()

template<size_t Separator, class ... AllTypes>
template<tool::MatchInputTypeConcept< tool::Inputs< Separator, AllTypes... > > CompatibleInputType_t>
void hh::Graph< Separator, AllTypes >::pushData ( std::shared_ptr< CompatibleInputType_t >  data)
inline

Push data into the graph.

Each input data is sent to all input nodes that match the input type that is sent.

Template Parameters
CompatibleInputType_tType on the input data
Parameters
dataData sent to the graph

Definition at line 287 of file graph.h.

◆ waitForTermination()

template<size_t Separator, class ... AllTypes>
void hh::Graph< Separator, AllTypes >::waitForTermination ( )
inline

Wait for the graph to terminate.

A graph terminate when all the threads it manages are terminated (i.e. when all the nodes are terminated)

Definition at line 291 of file graph.h.

Member Data Documentation

◆ coreGraph_

template<size_t Separator, class ... AllTypes>
std::shared_ptr<core::CoreGraph<Separator, AllTypes...> > const hh::Graph< Separator, AllTypes >::coreGraph_ = nullptr
private

Core of the graph.

Definition at line 147 of file graph.h.

◆ nodes_

template<size_t Separator, class ... AllTypes>
std::unique_ptr<std::set<std::shared_ptr<Node> > > hh::Graph< Separator, AllTypes >::nodes_ = nullptr
private

Set of nodes given by the end user.

Definition at line 149 of file graph.h.