task_manager: introduce new node types and dropping code smell 87/311387/8
authorInki Dae <inki.dae@samsung.com>
Mon, 20 May 2024 06:05:00 +0000 (15:05 +0900)
committerInki Dae <inki.dae@samsung.com>
Wed, 22 May 2024 01:14:56 +0000 (10:14 +0900)
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>
14 files changed:
services/auto_zoom/src/AutoZoom.cpp
services/task_manager/CMakeLists.txt
services/task_manager/include/BridgeNode.h [new file with mode: 0644]
services/task_manager/include/CallbackNode.h
services/task_manager/include/EndpointNode.h [new file with mode: 0644]
services/task_manager/include/INode.h
services/task_manager/include/InferenceNode.h
services/task_manager/include/TaskNode.h [new file with mode: 0644]
services/task_manager/include/TrainingNode.h [new file with mode: 0644]
services/task_manager/src/CallbackNode.cpp
services/task_manager/src/InferenceNode.cpp
services/task_manager/src/TaskManager.cpp
services/task_manager/src/TaskNode.cpp [new file with mode: 0644]
test/services/test_task_manager.cpp

index 4ed7a7ffccf726edf9eb253bc7acfe623ad7536d..72341a8d0e64082df632f19f4321a2c5d5588b87 100644 (file)
@@ -25,6 +25,7 @@
 #include "InputTypes.h"
 #include "Postprocessor.h"
 #include "InferenceNode.h"
+#include "EndpointNode.h"
 
 using namespace std;
 using namespace singleo::inference;
@@ -44,12 +45,18 @@ AutoZoom::AutoZoom()
        // 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>();
 }
 
index 76e71d8cef5fb5771ae4ac2e993c6e4a4ebe8b90..5ca6371d8731af25cda97f4891231e935af36428 100644 (file)
@@ -1,6 +1,7 @@
 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
 )
diff --git a/services/task_manager/include/BridgeNode.h b/services/task_manager/include/BridgeNode.h
new file mode 100644 (file)
index 0000000..ca9c095
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * 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
index 083dc3240d580f72817961021b5c2ee1ab968f7b..e15db159dd005a3a077dcd3a2c4e6fd5802120c1 100644 (file)
@@ -29,14 +29,13 @@ namespace services
 {
 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;
@@ -47,10 +46,6 @@ public:
        virtual ~CallbackNode() = default;
 
        NodeType getType() override;
-       void setName(std::string name) override
-       {
-               _name = name;
-       }
        std::string &getName() override
        {
                return _name;
@@ -68,6 +63,7 @@ public:
        NodeCb getCb();
        std::vector<std::shared_ptr<BaseResultType> > &getResults();
        void addResult(std::shared_ptr<BaseResultType> result);
+       void clearResults();
 };
 
 }
diff --git a/services/task_manager/include/EndpointNode.h b/services/task_manager/include/EndpointNode.h
new file mode 100644 (file)
index 0000000..e53882d
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * 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
index 9128bc714fde9cd705a9d06f4340ca9a51d73f3d..0cd68caffe07841431a9961b102fdb46c60421a8 100644 (file)
@@ -28,7 +28,7 @@ namespace singleo
 {
 namespace services
 {
-enum class NodeType { NONE, INFERENCE, CB };
+enum class NodeType { NONE, INFERENCE, TRAINING, BRIDGE, ENDPOINT };
 
 class INode
 {
@@ -36,7 +36,6 @@ public:
        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;
index 5aa097fe4e16bea6db66493146e73ce3b8f20b61..51748af72a0cd443394bee7d38c1e4d187f50b12 100644 (file)
@@ -20,7 +20,7 @@
 #include <mutex>
 #include <condition_variable>
 
-#include "INode.h"
+#include "TaskNode.h"
 #include "SingleoException.h"
 #include "IInferenceTaskInterface.h"
 
@@ -28,43 +28,24 @@ namespace singleo
 {
 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();
 };
 
 }
diff --git a/services/task_manager/include/TaskNode.h b/services/task_manager/include/TaskNode.h
new file mode 100644 (file)
index 0000000..3a48ab2
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * 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
diff --git a/services/task_manager/include/TrainingNode.h b/services/task_manager/include/TrainingNode.h
new file mode 100644 (file)
index 0000000..1dc8960
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * 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
index fcf9fbc19a67d272d37859c5cfac217036f84323..8b44ac588a43782eeff7cc1b6fc04097cf06801b 100644 (file)
@@ -78,6 +78,11 @@ vector<shared_ptr<BaseResultType> > &CallbackNode::getResults()
        return _results;
 }
 
+void CallbackNode::clearResults()
+{
+       _results.clear();
+}
+
 void CallbackNode::wait()
 {
        unique_lock<mutex> lock(_mutex);
index 3f68f20eb82e89ff1c95b432280ae97ec52dde33..877cacfe3b74fc1eb4ea6363b45bbbf64309f068 100644 (file)
@@ -23,21 +23,6 @@ namespace singleo
 {
 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);
@@ -48,43 +33,14 @@ IInferenceTaskInterface *InferenceNode::getInferenceTask()
        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();
 }
 
 }
index 90ac3ecf3bb518848d3995eca71367495b075ff5..3b47449c6a0327861429d61f5349dd33469c28b2 100644 (file)
@@ -18,8 +18,9 @@
 #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;
@@ -38,7 +39,6 @@ void TaskManager::threadCb(shared_ptr<INode> &node)
                        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.
@@ -47,11 +47,11 @@ void TaskManager::threadCb(shared_ptr<INode> &node)
                //     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];
@@ -59,7 +59,7 @@ void TaskManager::threadCb(shared_ptr<INode> &node)
                        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.
@@ -68,41 +68,57 @@ void TaskManager::threadCb(shared_ptr<INode> &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();
 }
@@ -138,6 +154,14 @@ void TaskManager::run()
                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) {
@@ -155,10 +179,8 @@ void TaskManager::run()
                        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)));
@@ -177,29 +199,10 @@ vector<shared_ptr<BaseResultType> > &TaskManager::output()
                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;
 }
diff --git a/services/task_manager/src/TaskNode.cpp b/services/task_manager/src/TaskNode.cpp
new file mode 100644 (file)
index 0000000..3eee34a
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * 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
index f0a0af8342f7cfff85d9a55e27c3a0f5e895d9e7..403e41d5f74f34654a95bb25f84b0074c98b8c4c 100644 (file)
@@ -24,7 +24,8 @@
 #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"
 
@@ -66,7 +67,7 @@ void BridgeNodeCallback(shared_ptr<INode> &node)
        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);
@@ -92,23 +93,31 @@ TEST(SingloTaskManager, MultipleNodesBasedGraphAShouldWork)
        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;
@@ -125,7 +134,7 @@ TEST(SingloTaskManager, MultipleNodesBasedGraphAShouldWork)
 
 // GraphB:
 //                -----> face_detection
-//         input |                     |----> callback ----> face_landmark_detection ----> output
+//         input |                     |----> bridge ----> face_landmark_detection ----> endpoint ----> output
 //                -----> face_detection
 TEST(SingloTaskManager, MultipleNodesBasedGraphBShouldWork)
 {
@@ -152,29 +161,30 @@ 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;
@@ -202,8 +212,8 @@ void LastNodeCallback(shared_ptr<INode> &node)
 }
 
 // GraphC:
-//                                        -----> callback -----> face_landmark_detection ------
-//         input -----> face_detection --|                                                     |----> callback ----> output
+//                                        -----> bridge -----> face_landmark_detection ------
+//         input -----> face_detection --|                                                     |----> endpoint ----> output
 //                                        -----------------------------------------------------
 TEST(SingloTaskManager, MultipleNodesBasedGraphDShouldWork)
 {
@@ -230,25 +240,21 @@ 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);