parallelTraversalTasks.h
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8 * See LICENSE for the license information
9 
10 * -------------------------------------------------------------------------- */
11 
17 #pragma once
18 
19 #include <gtsam/global_includes.h>
20 
21 #include <boost/shared_ptr.hpp>
22 #include <boost/make_shared.hpp>
23 
24 #ifdef GTSAM_USE_TBB
25 #include <tbb/task.h> // tbb::task, tbb::task_list
26 #include <tbb/scalable_allocator.h> // tbb::scalable_allocator
27 
28 namespace gtsam {
29 
31  namespace treeTraversal {
32 
33  namespace internal {
34 
35  /* ************************************************************************* */
36  template<typename NODE, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
37  class PreOrderTask : public tbb::task
38  {
39  public:
40  const boost::shared_ptr<NODE>& treeNode;
41  boost::shared_ptr<DATA> myData;
42  VISITOR_PRE& visitorPre;
43  VISITOR_POST& visitorPost;
44  int problemSizeThreshold;
45  bool makeNewTasks;
46 
47  bool isPostOrderPhase;
48 
49  PreOrderTask(const boost::shared_ptr<NODE>& treeNode, const boost::shared_ptr<DATA>& myData,
50  VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost, int problemSizeThreshold,
51  bool makeNewTasks = true)
52  : treeNode(treeNode),
53  myData(myData),
54  visitorPre(visitorPre),
55  visitorPost(visitorPost),
56  problemSizeThreshold(problemSizeThreshold),
57  makeNewTasks(makeNewTasks),
58  isPostOrderPhase(false) {}
59 
60  tbb::task* execute() override
61  {
62  if(isPostOrderPhase)
63  {
64  // Run the post-order visitor since this task was recycled to run the post-order visitor
65  (void) visitorPost(treeNode, *myData);
66  return nullptr;
67  }
68  else
69  {
70  if(makeNewTasks)
71  {
72  if(!treeNode->children.empty())
73  {
74  // Allocate post-order task as a continuation
75  isPostOrderPhase = true;
76  recycle_as_continuation();
77 
78  bool overThreshold = (treeNode->problemSize() >= problemSizeThreshold);
79 
80  tbb::task* firstChild = 0;
81  tbb::task_list childTasks;
82  for(const boost::shared_ptr<NODE>& child: treeNode->children)
83  {
84  // Process child in a subtask. Important: Run visitorPre before calling
85  // allocate_child so that if visitorPre throws an exception, we will not have
86  // allocated an extra child, this causes a TBB error.
87  boost::shared_ptr<DATA> childData = boost::allocate_shared<DATA>(
88  tbb::scalable_allocator<DATA>(), visitorPre(child, *myData));
89  tbb::task* childTask =
90  new (allocate_child()) PreOrderTask(child, childData, visitorPre, visitorPost,
91  problemSizeThreshold, overThreshold);
92  if (firstChild)
93  childTasks.push_back(*childTask);
94  else
95  firstChild = childTask;
96  }
97 
98  // If we have child tasks, start subtasks and wait for them to complete
99  set_ref_count((int)treeNode->children.size());
100  spawn(childTasks);
101  return firstChild;
102  }
103  else
104  {
105  // Run the post-order visitor in this task if we have no children
106  (void) visitorPost(treeNode, *myData);
107  return nullptr;
108  }
109  }
110  else
111  {
112  // Process this node and its children in this task
113  processNodeRecursively(treeNode, *myData);
114  return nullptr;
115  }
116  }
117  }
118 
119  void processNodeRecursively(const boost::shared_ptr<NODE>& node, DATA& myData)
120  {
121  for(const boost::shared_ptr<NODE>& child: node->children)
122  {
123  DATA childData = visitorPre(child, myData);
124  processNodeRecursively(child, childData);
125  }
126 
127  // Run the post-order visitor
128  (void) visitorPost(node, myData);
129  }
130  };
131 
132  /* ************************************************************************* */
133  template<typename ROOTS, typename NODE, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
134  class RootTask : public tbb::task
135  {
136  public:
137  const ROOTS& roots;
138  DATA& myData;
139  VISITOR_PRE& visitorPre;
140  VISITOR_POST& visitorPost;
141  int problemSizeThreshold;
142  RootTask(const ROOTS& roots, DATA& myData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost,
143  int problemSizeThreshold) :
144  roots(roots), myData(myData), visitorPre(visitorPre), visitorPost(visitorPost),
145  problemSizeThreshold(problemSizeThreshold) {}
146 
147  tbb::task* execute() override
148  {
149  typedef PreOrderTask<NODE, DATA, VISITOR_PRE, VISITOR_POST> PreOrderTask;
150  // Create data and tasks for our children
151  tbb::task_list tasks;
152  for(const boost::shared_ptr<NODE>& root: roots)
153  {
154  boost::shared_ptr<DATA> rootData = boost::allocate_shared<DATA>(tbb::scalable_allocator<DATA>(), visitorPre(root, myData));
155  tasks.push_back(*new(allocate_child())
156  PreOrderTask(root, rootData, visitorPre, visitorPost, problemSizeThreshold));
157  }
158  // Set TBB ref count
159  set_ref_count(1 + (int) roots.size());
160  // Spawn tasks
161  spawn_and_wait_for_all(tasks);
162  // Return nullptr
163  return nullptr;
164  }
165  };
166 
167  template<typename NODE, typename ROOTS, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
168  RootTask<ROOTS, NODE, DATA, VISITOR_PRE, VISITOR_POST>&
169  CreateRootTask(const ROOTS& roots, DATA& rootData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost, int problemSizeThreshold)
170  {
171  typedef RootTask<ROOTS, NODE, DATA, VISITOR_PRE, VISITOR_POST> RootTask;
172  return *new(tbb::task::allocate_root()) RootTask(roots, rootData, visitorPre, visitorPost, problemSizeThreshold);
173  }
174 
175  }
176 
177  }
178 
179 }
180 
181 #endif
const boost::shared_ptr< NODE > & treeNode
const mpreal root(const mpreal &x, unsigned long int k, mp_rnd_t r=mpreal::get_default_rnd())
Definition: mpreal.h:2194
Included from all GTSAM files.
traits
Definition: chartTesting.h:28


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:43:07