Introduce new node types and dropping implicit use of CallbackNode.
Until now, CallbackNode had been used for two purposes implicitly
- one is for bridge and other is endpoint.
So this patch separates CallbackNode into two nodes - BridgeNode and
EndpointNode - so that CallbackNode can be used explicitly, and also
separates InferenceNode into two nodes - InferenceNode and TrainingNode
- by making these two classes to be derived from TaskNode.
As summary,
- InferenceNode and TrainingNode are derived from TaskNode which is able
to perform inference or training through machine learning framework.
- BridgeNode and EndpointNode are derived from CallbackNode which is able
to call an callback registered by user.
With this patch, graph rule of task manager is as follows,
1. Start node should be task node such as InferenceNode and TrainingNode.
2. Last node should be EndpointNode.
3. BridgeNode should be placed bewteen two task nodes such as InferenceNode
and TrainingNode.
4. BridgeNode should have a valid callback but it's optional for other types
of callback nodes.
5. Multiple endpoint nodes can exist.
Change-Id: I4d2917d15cededc3fd11a93afd2db4b6fe5cbe5c
Signed-off-by: Inki Dae <inki.dae@samsung.com>
#include "InputTypes.h"
#include "Postprocessor.h"
#include "InferenceNode.h"
+#include "EndpointNode.h"
using namespace std;
using namespace singleo::inference;
// In default, we will use Inference service factory for Mediavision to use Mediavision framework
// for inference service. TODO. introduce meta config file approach later.
auto factory = InferenceTaskFactory::instance().create("MvInferenceTaskFactory");
- auto face_detection_node = make_shared<InferenceNode>();
+ auto face_detection_node = make_shared<InferenceNode>("face_detection");
- face_detection_node->setName("face_detection");
face_detection_node->setInferenceTask(factory->createFaceDetection());
_taskManager = make_unique<TaskManager>();
_taskManager->addNode(face_detection_node);
+
+ auto endpoint_node = make_shared<EndpointNode>();
+
+ endpoint_node->setCb(nullptr);
+ endpoint_node->addDependency(face_detection_node);
+ _taskManager->addNode(endpoint_node);
+
_postprocessor = make_unique<Postprocessor>();
}
SET(SINGLEO_SERVICE_SOURCE_FILES
${SINGLEO_SERVICE_SOURCE_FILES}
task_manager/src/TaskManager.cpp
+ task_manager/src/TaskNode.cpp
task_manager/src/InferenceNode.cpp
task_manager/src/CallbackNode.cpp
)
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BRIDGE_NODE_H__
+#define __BRIDGE_NODE_H__
+
+#include "CallbackNode.h"
+
+namespace singleo
+{
+namespace services
+{
+class BridgeNode : public CallbackNode
+{
+public:
+ BridgeNode(std::string name = "bridge")
+ {
+ _name = name;
+ _type = NodeType::BRIDGE;
+ }
+ virtual ~BridgeNode() = default;
+};
+
+}
+}
+
+#endif
\ No newline at end of file
{
class CallbackNode : public INode
{
-private:
+protected:
+ NodeType _type { NodeType::NONE };
std::string _name;
- NodeType _type { NodeType::CB };
std::vector<std::shared_ptr<INode> > _dependencies;
NodeCb _cb;
std::vector<std::shared_ptr<BaseDataType> > _inputs;
std::shared_ptr<BaseDataType> _output;
- // _results should be updated by user callback.
std::vector<std::shared_ptr<BaseResultType> > _results;
bool _completed { false };
std::condition_variable _event;
virtual ~CallbackNode() = default;
NodeType getType() override;
- void setName(std::string name) override
- {
- _name = name;
- }
std::string &getName() override
{
return _name;
NodeCb getCb();
std::vector<std::shared_ptr<BaseResultType> > &getResults();
void addResult(std::shared_ptr<BaseResultType> result);
+ void clearResults();
};
}
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ENDPOINT_NODE_H__
+#define __ENDPOINT_NODE_H__
+
+#include <mutex>
+#include <condition_variable>
+
+#include "CallbackNode.h"
+#include "SingleoException.h"
+
+namespace singleo
+{
+namespace services
+{
+class EndpointNode : public CallbackNode
+{
+public:
+ EndpointNode(std::string name = "endpoint")
+ {
+ _name = name;
+ _type = NodeType::ENDPOINT;
+ }
+ virtual ~EndpointNode() = default;
+};
+
+}
+}
+
+#endif
\ No newline at end of file
{
namespace services
{
-enum class NodeType { NONE, INFERENCE, CB };
+enum class NodeType { NONE, INFERENCE, TRAINING, BRIDGE, ENDPOINT };
class INode
{
virtual ~INode() {};
virtual NodeType getType() = 0;
- virtual void setName(std::string name) = 0;
virtual std::string &getName() = 0;
virtual void addInput(std::shared_ptr<BaseDataType> input) = 0;
virtual std::vector<std::shared_ptr<BaseDataType> > &getInputs() = 0;
#include <mutex>
#include <condition_variable>
-#include "INode.h"
+#include "TaskNode.h"
#include "SingleoException.h"
#include "IInferenceTaskInterface.h"
{
namespace services
{
-class InferenceNode : public INode
+class InferenceNode : public TaskNode
{
private:
- NodeType _type { NodeType::INFERENCE };
- std::string _name;
std::unique_ptr<inference::IInferenceTaskInterface> _task;
- std::vector<std::shared_ptr<INode> > _dependencies;
- std::vector<std::shared_ptr<BaseDataType> > _inputs;
- std::shared_ptr<BaseDataType> _output;
- bool _completed { false };
- std::condition_variable _event;
- std::mutex _mutex;
+ std::mutex _resultMutex;
public:
- InferenceNode() = default;
- virtual ~InferenceNode() = default;
-
- NodeType getType() override;
- void setName(std::string name) override
+ InferenceNode(std::string name = "inference")
{
_name = name;
+ _type = NodeType::INFERENCE;
}
- std::string &getName() override
- {
- return _name;
- }
- void addInput(std::shared_ptr<BaseDataType> input) override;
- std::vector<std::shared_ptr<BaseDataType> > &getInputs() override;
- void addDependency(std::shared_ptr<INode> node) override;
- std::vector<std::shared_ptr<INode> > &getDependencies() override;
- void setOutput(std::shared_ptr<BaseDataType> output) override;
- std::shared_ptr<BaseDataType> &getOutput() override;
- void wait() override;
- void wakeup() override;
+ virtual ~InferenceNode() = default;
void setInferenceTask(std::unique_ptr<inference::IInferenceTaskInterface> &&task);
inference::IInferenceTaskInterface *getInferenceTask();
+ void lockResult();
+ void unlockResult();
};
}
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TASK_NODE_H__
+#define __TASK_NODE_H__
+
+#include <mutex>
+#include <condition_variable>
+
+#include "INode.h"
+#include "SingleoException.h"
+
+namespace singleo
+{
+namespace services
+{
+class TaskNode : public INode
+{
+protected:
+ NodeType _type { NodeType::NONE };
+ std::string _name;
+ std::vector<std::shared_ptr<INode> > _dependencies;
+ std::vector<std::shared_ptr<BaseDataType> > _inputs;
+ std::shared_ptr<BaseDataType> _output;
+ bool _completed { false };
+ std::condition_variable _event;
+ std::mutex _mutex;
+
+public:
+ TaskNode() = default;
+ virtual ~TaskNode() = default;
+
+ NodeType getType() override;
+ std::string &getName() override
+ {
+ return _name;
+ }
+ void addInput(std::shared_ptr<BaseDataType> input) override;
+ std::vector<std::shared_ptr<BaseDataType> > &getInputs() override;
+ void addDependency(std::shared_ptr<INode> node) override;
+ std::vector<std::shared_ptr<INode> > &getDependencies() override;
+ void setOutput(std::shared_ptr<BaseDataType> output) override;
+ std::shared_ptr<BaseDataType> &getOutput() override;
+ void wait() override;
+ void wakeup() override;
+};
+
+}
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TRAINING_NODE_H__
+#define __TRAINING_NODE_H__
+
+#include <mutex>
+#include <condition_variable>
+
+#include "TaskNode.h"
+#include "SingleoException.h"
+#include "IInferenceTaskInterface.h"
+
+namespace singleo
+{
+namespace services
+{
+class TrainingNode : public TaskNode
+{
+private:
+ // TODO. define ITrainingTaskInterface here.
+
+public:
+ TrainingNode(std::string name = "training")
+ {
+ _name = name;
+ _type = NodeType::TRAINING;
+ }
+ virtual ~TrainingNode() = default;
+
+ // TODO. define setTrainingTask and getTrainingTask here.
+};
+
+}
+}
+
+#endif
\ No newline at end of file
return _results;
}
+void CallbackNode::clearResults()
+{
+ _results.clear();
+}
+
void CallbackNode::wait()
{
unique_lock<mutex> lock(_mutex);
{
namespace services
{
-NodeType InferenceNode::getType()
-{
- return _type;
-}
-
-void InferenceNode::addInput(shared_ptr<BaseDataType> input)
-{
- _inputs.push_back(input);
-}
-
-vector<shared_ptr<BaseDataType> > &InferenceNode::getInputs()
-{
- return _inputs;
-}
-
void InferenceNode::setInferenceTask(unique_ptr<inference::IInferenceTaskInterface> &&task)
{
_task = move(task);
return _task.get();
}
-void InferenceNode::addDependency(std::shared_ptr<INode> node)
-{
- _dependencies.push_back(node);
-}
-
-std::vector<std::shared_ptr<INode> > &InferenceNode::getDependencies()
+void InferenceNode::lockResult()
{
- return _dependencies;
+ _resultMutex.lock();
}
-void InferenceNode::setOutput(std::shared_ptr<BaseDataType> output)
+void InferenceNode::unlockResult()
{
- _output = dynamic_pointer_cast<ImageDataType>(output);
-}
-
-std::shared_ptr<BaseDataType> &InferenceNode::getOutput()
-{
- return _output;
-}
-
-void InferenceNode::wait()
-{
- unique_lock<mutex> lock(_mutex);
-
- // If already completed then just return.
- if (_completed)
- return;
-
- _event.wait(lock, [this] { return this->_completed; });
-}
-
-void InferenceNode::wakeup()
-{
- unique_lock<mutex> lock(_mutex);
-
- _completed = true;
- _event.notify_all();
+ _resultMutex.unlock();
}
}
#include "SingleoException.h"
#include "SingleoLog.h"
#include "TaskManager.h"
-#include "CallbackNode.h"
#include "InferenceNode.h"
+#include "BridgeNode.h"
+#include "EndpointNode.h"
using namespace std;
using namespace singleo::exception;
throw InvalidOperation("Invalid input data type");
}
- shared_ptr<ImageDataType> input;
auto inferenceNode = dynamic_pointer_cast<InferenceNode>(node);
// If no dependency then use input of current node as input source.
// output(inference_node_c) - will be used as input source like below graph,
//
// inference_node_a -----
- // |------ Callback_node ------- inference_node_c
+ // |------ bridge_node ------- inference_node_c ------ endpoint_node
// inference_node_b -----
//
- // If InferenceNode has dependency node then the dependency node must be CallbackNode like above graph.
- // Add output from the CallbackNode to InferenceNode as input.
+ // If InferenceNode has dependency node then the dependency node must be BridgeNode like above graph.
+ // Add output from the BridgeNode to InferenceNode as input.
if (!inferenceNode->getDependencies().empty()) {
// TODO. consider for multiple dependencies later.
auto &callbackNode = inferenceNode->getDependencies()[0];
inferenceNode->addInput(callbackNode->getOutput());
}
- input = dynamic_pointer_cast<ImageDataType>(inferenceNode->getInputs()[0]);
+ auto input = dynamic_pointer_cast<ImageDataType>(inferenceNode->getInputs()[0]);
inferenceNode->getInferenceTask()->invoke(*input);
// Inference request has been completed so release input data if the data was internally allocated by callback node.
// Service request to 'input' has been completed so clean up it.
inferenceNode->getInputs().clear();
- } else if (node->getType() == NodeType::CB) {
- auto callbackNode = dynamic_pointer_cast<CallbackNode>(node);
- NodeCb cb = callbackNode->getCb();
- if (!cb) {
- SINGLEO_LOGE("Callback function is null.");
- throw InvalidOperation("Callback function is null.");
- }
- for (auto &n : node->getDependencies()) {
- // Add the result if dependency node is inference service not callback.
- if (n->getType() == NodeType::INFERENCE) {
- auto inferenceNode = dynamic_pointer_cast<InferenceNode>(n);
- auto &result = inferenceNode->getInferenceTask()->result();
-
- if (result._type == ResultType::FACE_DETECTION)
- callbackNode->addResult(make_shared<FdResultType>(
- dynamic_cast<FdResultType &>(inferenceNode->getInferenceTask()->result())));
- else if (result._type == ResultType::FACE_LANDMARK)
- callbackNode->addResult(make_shared<FldResultType>(
- dynamic_cast<FldResultType &>(inferenceNode->getInferenceTask()->result())));
- else if (result._type == ResultType::OBJECT_DETECTION)
- callbackNode->addResult(make_shared<OdResultType>(
- dynamic_cast<OdResultType &>(inferenceNode->getInferenceTask()->result())));
- }
+ // Wake up.
+ node->wakeup();
+ return;
+ }
+
+ // ALl other types of callback nodes are handled here.
+ // TODO. Other callback style nodes such as StoreNode, DebugNode and so on will be added later.
+ auto callbackNode = dynamic_pointer_cast<CallbackNode>(node);
+
+ callbackNode->clearResults();
+ auto cb = callbackNode->getCb();
+ if (node->getType() == NodeType::BRIDGE && !cb) {
+ SINGLEO_LOGE("Bridge node needs callback.");
+ throw InvalidOperation("Bridge node needs callback.");
+ }
+
+ for (auto &n : node->getDependencies()) {
+ if (n->getType() != NodeType::INFERENCE) {
+ SINGLEO_LOGE("Dependency node should be Inference node.");
+ throw InvalidOperation("Dependency node should be Inference node.");
}
- // TODO. consider for mulitple inputs later.
- node->addInput(_inputs[0]);
+ auto inferenceNode = dynamic_pointer_cast<InferenceNode>(n);
- // Call the callback function registered in this callback node.
- // In this callback, new data should be set by calling node->setOutput()
- // if new data is made. TODO. consider for multiple inputs later.
- cb(node);
+ inferenceNode->lockResult();
+
+ auto &result = inferenceNode->getInferenceTask()->result();
+
+ if (result._type == ResultType::FACE_DETECTION)
+ callbackNode->addResult(make_shared<FdResultType>(
+ dynamic_cast<FdResultType &>(inferenceNode->getInferenceTask()->result())));
+ else if (result._type == ResultType::FACE_LANDMARK)
+ callbackNode->addResult(make_shared<FldResultType>(
+ dynamic_cast<FldResultType &>(inferenceNode->getInferenceTask()->result())));
+ else if (result._type == ResultType::OBJECT_DETECTION)
+ callbackNode->addResult(make_shared<OdResultType>(
+ dynamic_cast<OdResultType &>(inferenceNode->getInferenceTask()->result())));
+
+ inferenceNode->unlockResult();
}
+ // TODO. consider for mulitple inputs later.
+ node->addInput(_inputs[0]);
+
+ // Call the callback function registered in this callback node.
+ // In this callback, new data should be set by calling node->setOutput()
+ // if new data is made. TODO. consider for multiple inputs later.
+ if (cb)
+ cb(node);
+
// Wake up.
node->wakeup();
}
throw InvalidOperation("No input source.");
}
+ // TODO. verify if current graph is valid or not here like below,
+ // 1. This graph should be DAG.
+ // 2. Start node should be Job node such as InferenceNode and TrainingNode.
+ // 3. Last node should be EndpointNode.
+ // 4. BridgeNode should be placed bewteen two Job nodes such as InferenceNode and TrainingNode.
+ // 5. BridgeNode should have a valid callback but it's optional for other types of callback nodes.
+ // 6. Multiple endpoint nodes can exist.
+
std::vector<std::unique_ptr<std::thread> > threads;
for (auto &n : _nodes) {
n->addInput(_inputs[0]);
}
- vector<shared_ptr<INode> > &dependencies = n->getDependencies();
-
// Wait until all nodes added to this node as dependency are completed
- for (auto &d : dependencies)
+ for (auto &d : n->getDependencies())
d->wait();
threads.push_back(make_unique<thread>(&TaskManager::threadCb, this, std::ref(n)));
throw InvalidOperation("Node is not set");
}
- auto lastNode = _nodes.back();
+ auto lastNode = dynamic_pointer_cast<EndpointNode>(_nodes.back());
_results.clear();
-
- // TODO. consider for callback node support as last node.
- if (lastNode->getType() == NodeType::INFERENCE) {
- auto inferenceNode = dynamic_pointer_cast<InferenceNode>(lastNode);
- auto &result = inferenceNode->getInferenceTask()->result();
- if (result._type == ResultType::FACE_DETECTION) {
- auto fd_result = dynamic_cast<FdResultType &>(result);
- _results.push_back(make_shared<FdResultType>(fd_result));
- } else if (result._type == ResultType::FACE_LANDMARK) {
- auto fld_result = dynamic_cast<FldResultType &>(result);
- _results.push_back(make_shared<FldResultType>(fld_result));
- } else if (result._type == ResultType::OBJECT_DETECTION) {
- auto od_result = dynamic_cast<OdResultType &>(result);
- _results.push_back(make_shared<OdResultType>(od_result));
- }
- } else {
- auto callbackNode = dynamic_pointer_cast<CallbackNode>(lastNode);
-
- _results = callbackNode->getResults();
- }
+ _results = lastNode->getResults();
return _results;
}
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TaskNode.h"
+
+using namespace std;
+
+namespace singleo
+{
+namespace services
+{
+NodeType TaskNode::getType()
+{
+ return _type;
+}
+
+void TaskNode::addInput(shared_ptr<BaseDataType> input)
+{
+ _inputs.push_back(input);
+}
+
+vector<shared_ptr<BaseDataType> > &TaskNode::getInputs()
+{
+ return _inputs;
+}
+
+void TaskNode::addDependency(std::shared_ptr<INode> node)
+{
+ _dependencies.push_back(node);
+}
+
+std::vector<std::shared_ptr<INode> > &TaskNode::getDependencies()
+{
+ return _dependencies;
+}
+
+void TaskNode::setOutput(std::shared_ptr<BaseDataType> output)
+{
+ _output = dynamic_pointer_cast<ImageDataType>(output);
+}
+
+std::shared_ptr<BaseDataType> &TaskNode::getOutput()
+{
+ return _output;
+}
+
+void TaskNode::wait()
+{
+ unique_lock<mutex> lock(_mutex);
+
+ // If already completed then just return.
+ if (_completed)
+ return;
+
+ _event.wait(lock, [this] { return this->_completed; });
+}
+
+void TaskNode::wakeup()
+{
+ unique_lock<mutex> lock(_mutex);
+
+ _completed = true;
+ _event.notify_all();
+}
+
+}
+}
\ No newline at end of file
#include "SingleoCommonTypes.h"
#include "TaskManager.h"
#include "InferenceNode.h"
-#include "CallbackNode.h"
+#include "BridgeNode.h"
+#include "EndpointNode.h"
#define IMG_FACE TEST_RES_PATH "/usr/share/capi-media-vision/res/inference/images/faceDetection.jpg"
callbackNode->setOutput(make_shared<ImageDataType>(newImage));
}
-// GraphA : input ----> face_detection ----> callback ----> face_landmark_detection ----> output
+// GraphA : input ----> face_detection ----> bridge ----> face_landmark_detection ----> endpoint ----> output
TEST(SingloTaskManager, MultipleNodesBasedGraphAShouldWork)
{
cv::Mat cv_image = cv::imread(IMG_FACE, cv::IMREAD_COLOR);
for (unsigned int cnt = 0; cnt < maxIteration; ++cnt) {
taskManager->addInput(image_data);
- auto face_detection_node = make_shared<InferenceNode>();
- face_detection_node->setName("face_detection");
+ auto face_detection_node = make_shared<InferenceNode>("face_detection");
face_detection_node->setInferenceTask(factory->createFaceDetection());
taskManager->addNode(face_detection_node);
- auto callback_node = make_shared<CallbackNode>();
- callback_node->setName("callback");
+ auto callback_node = make_shared<BridgeNode>();
callback_node->setCb(BridgeNodeCallback);
callback_node->addDependency(face_detection_node);
taskManager->addNode(callback_node);
- auto face_landmark_node = make_shared<InferenceNode>();
- face_landmark_node->setName("face_landmark");
+ auto face_landmark_node = make_shared<InferenceNode>("face_landmark");
face_landmark_node->setInferenceTask(factory->createFaceLandmarkDetection());
face_landmark_node->addDependency(callback_node);
taskManager->addNode(face_landmark_node);
+ auto endpoint_node = make_shared<EndpointNode>();
+ endpoint_node->setCb(nullptr);
+ endpoint_node->addDependency(face_landmark_node);
+ taskManager->addNode(endpoint_node);
+
+ auto endpoint_node1 = make_shared<EndpointNode>("endpoint1");
+ endpoint_node1->setCb(nullptr);
+ endpoint_node1->addDependency(face_landmark_node);
+ taskManager->addNode(endpoint_node1);
+
+
taskManager->run();
cout << "Face landmark result" << endl;
// GraphB:
// -----> face_detection
-// input | |----> callback ----> face_landmark_detection ----> output
+// input | |----> bridge ----> face_landmark_detection ----> endpoint ----> output
// -----> face_detection
TEST(SingloTaskManager, MultipleNodesBasedGraphBShouldWork)
{
for (unsigned int cnt = 0; cnt < maxIteration; ++cnt) {
taskManager->addInput(image_data);
- auto face_detection_node_a = make_shared<InferenceNode>();
- face_detection_node_a->setName("face_detectionA");
+ auto face_detection_node_a = make_shared<InferenceNode>("face_detectionA");
face_detection_node_a->setInferenceTask(factory->createFaceDetection());
taskManager->addNode(face_detection_node_a);
- auto face_detection_node_b = make_shared<InferenceNode>();
- face_detection_node_b->setName("face_detectionB");
+ auto face_detection_node_b = make_shared<InferenceNode>("face_detectionB");
face_detection_node_b->setInferenceTask(factory->createFaceDetection());
taskManager->addNode(face_detection_node_b);
- auto callback_node = make_shared<CallbackNode>();
- callback_node->setName("callback");
+ auto callback_node = make_shared<BridgeNode>();
callback_node->setCb(BridgeNodeCallback);
callback_node->addDependency(face_detection_node_a);
callback_node->addDependency(face_detection_node_b);
taskManager->addNode(callback_node);
- auto face_landmark_node = make_shared<InferenceNode>();
- face_landmark_node->setName("face_landmark");
+ auto face_landmark_node = make_shared<InferenceNode>("face_landmark");
face_landmark_node->setInferenceTask(factory->createFaceLandmarkDetection());
face_landmark_node->addDependency(callback_node);
taskManager->addNode(face_landmark_node);
+ auto endpoint_node = make_shared<EndpointNode>();
+ endpoint_node->setCb(nullptr);
+ endpoint_node->addDependency(face_landmark_node);
+ taskManager->addNode(endpoint_node);
+
taskManager->run();
cout << "Face landmark result" << endl;
}
// GraphC:
-// -----> callback -----> face_landmark_detection ------
-// input -----> face_detection --| |----> callback ----> output
+// -----> bridge -----> face_landmark_detection ------
+// input -----> face_detection --| |----> endpoint ----> output
// -----------------------------------------------------
TEST(SingloTaskManager, MultipleNodesBasedGraphDShouldWork)
{
for (unsigned int cnt = 0; cnt < maxIteration; ++cnt) {
taskManager->addInput(image_data);
- auto face_detection_node = make_shared<InferenceNode>();
- face_detection_node->setName("face_detection");
+ auto face_detection_node = make_shared<InferenceNode>("face_detection");
face_detection_node->setInferenceTask(factory->createFaceDetection());
taskManager->addNode(face_detection_node);
- auto bridge_callback_node = make_shared<CallbackNode>();
- bridge_callback_node->setName("bridge_callback");
+ auto bridge_callback_node = make_shared<BridgeNode>();
bridge_callback_node->setCb(BridgeNodeCallback);
bridge_callback_node->addDependency(face_detection_node);
taskManager->addNode(bridge_callback_node);
- auto face_landmark_node = make_shared<InferenceNode>();
- face_landmark_node->setName("face_landmark");
+ auto face_landmark_node = make_shared<InferenceNode>("face_landmark");
face_landmark_node->setInferenceTask(factory->createFaceLandmarkDetection());
face_landmark_node->addDependency(bridge_callback_node);
taskManager->addNode(face_landmark_node);
- auto lase_callback_node = make_shared<CallbackNode>();
- lase_callback_node->setName("last_callback");
+ auto lase_callback_node = make_shared<EndpointNode>();
lase_callback_node->setCb(LastNodeCallback);
lase_callback_node->addDependency(face_detection_node);
lase_callback_node->addDependency(face_landmark_node);