From 6f463166a9bb6f3bb0984281cb6db82e2759145e Mon Sep 17 00:00:00 2001 From: Richard Roberts Date: Fri, 27 Sep 2013 16:30:36 +0000 Subject: [PATCH] Using TBB task continuation in tree traversal but this unfortunately does not improve performance --- gtsam/base/treeTraversal-inst.h | 105 ++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 40 deletions(-) diff --git a/gtsam/base/treeTraversal-inst.h b/gtsam/base/treeTraversal-inst.h index 523fad558..9b3229d8e 100644 --- a/gtsam/base/treeTraversal-inst.h +++ b/gtsam/base/treeTraversal-inst.h @@ -62,71 +62,95 @@ namespace gtsam { #ifdef GTSAM_USE_TBB - // Internal node used in parallel traversal stack - template - struct ParallelTraversalNode { + /* ************************************************************************* */ + template + class PostOrderTask : public tbb::task + { + public: const boost::shared_ptr& treeNode; - DATA myData; - ParallelTraversalNode(const boost::shared_ptr& treeNode, const DATA& myData) : - treeNode(treeNode), myData(myData) {} + boost::shared_ptr myData; + VISITOR_POST& visitorPost; + + PostOrderTask(const boost::shared_ptr& treeNode, const boost::shared_ptr& myData, VISITOR_POST& visitorPost) : + treeNode(treeNode), myData(myData), visitorPost(visitorPost) {} + + tbb::task* execute() + { + // Run the post-order visitor + (void) visitorPost(treeNode, *myData); + + return NULL; + } }; + /* ************************************************************************* */ template class PreOrderTask : public tbb::task { public: const boost::shared_ptr& treeNode; - DATA myData; + boost::shared_ptr myData; VISITOR_PRE& visitorPre; VISITOR_POST& visitorPost; int problemSizeThreshold; bool makeNewTasks; - PreOrderTask(const boost::shared_ptr& treeNode, const DATA& myData, + + PreOrderTask(const boost::shared_ptr& treeNode, const boost::shared_ptr& myData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost, int problemSizeThreshold, bool makeNewTasks = true) : treeNode(treeNode), myData(myData), visitorPre(visitorPre), visitorPost(visitorPost), problemSizeThreshold(problemSizeThreshold), makeNewTasks(makeNewTasks) {} - typedef ParallelTraversalNode ParallelTraversalNodeType; - tbb::task* execute() { - // Process this node and its children - processNode(treeNode, myData); + if (makeNewTasks) + { + if(!treeNode->children.empty()) + { + // Allocate post-order task as a continuation + PostOrderTask& postOrderTask = + *new(allocate_continuation()) PostOrderTask(treeNode, myData, visitorPost); + + bool overThreshold = (treeNode->problemSize() >= problemSizeThreshold); + + tbb::task_list childTasks; + BOOST_FOREACH(const boost::shared_ptr& child, treeNode->children) + { + // Process child in a subtask. Important: Run visitorPre before calling + // allocate_child so that if visitorPre throws an exception, we will not have + // allocated an extra child, this causes a TBB error. + boost::shared_ptr childData = boost::allocate_shared(tbb::scalable_allocator(), visitorPre(child, *myData)); + childTasks.push_back(*new(postOrderTask.allocate_child()) + PreOrderTask(child, childData, visitorPre, visitorPost, + problemSizeThreshold, overThreshold)); + } + + // If we have child tasks, start subtasks and wait for them to complete + postOrderTask.set_ref_count((int) treeNode->children.size()); + spawn(childTasks); + } + else + { + // Run the post-order visitor in this task if we have no children + (void) visitorPost(treeNode, *myData); + } + } + else + { + // Process this node and its children in this task + processNodeRecursively(treeNode, *myData); + } // Return NULL return NULL; } - void processNode(const boost::shared_ptr& node, DATA& myData) + void processNodeRecursively(const boost::shared_ptr& node, DATA& myData) { - if(makeNewTasks) + BOOST_FOREACH(const boost::shared_ptr& child, node->children) { - bool overThreshold = (node->problemSize() >= problemSizeThreshold); - - tbb::task_list childTasks; - BOOST_FOREACH(const boost::shared_ptr& child, node->children) - { - // Process child in a subtask. Important: Run visitorPre before calling - // allocate_child so that if visitorPre throws an exception, we will not have - // allocated an extra child, this causes a TBB error. - const DATA childData = visitorPre(child, myData); - childTasks.push_back(*new(allocate_child()) - PreOrderTask(child, childData, visitorPre, visitorPost, - problemSizeThreshold, overThreshold)); - } - - // If we have child tasks, start subtasks and wait for them to complete - set_ref_count(1 + (int)node->children.size()); - spawn_and_wait_for_all(childTasks); - } - else - { - BOOST_FOREACH(const boost::shared_ptr& child, node->children) - { - DATA childData = visitorPre(child, myData); - processNode(child, childData); - } + DATA childData = visitorPre(child, myData); + processNodeRecursively(child, childData); } // Run the post-order visitor @@ -134,6 +158,7 @@ namespace gtsam { } }; + /* ************************************************************************* */ template class RootTask : public tbb::task { @@ -155,7 +180,7 @@ namespace gtsam { tbb::task_list tasks; BOOST_FOREACH(const boost::shared_ptr& root, roots) { - DATA rootData = visitorPre(root, myData); + boost::shared_ptr rootData = boost::allocate_shared(tbb::scalable_allocator(), visitorPre(root, myData)); tasks.push_back(*new(allocate_child()) PreOrderTask(root, rootData, visitorPre, visitorPost, problemSizeThreshold)); }