First attempt at small node agglomeration

release/4.3a0
Richard Roberts 2013-07-26 01:10:17 +00:00
parent 3118f6bb9f
commit 1b263e4bdb
1 changed files with 89 additions and 33 deletions

View File

@ -48,47 +48,92 @@ namespace gtsam {
expanded(false), treeNode(_treeNode), parentData(_parentData) {} expanded(false), treeNode(_treeNode), parentData(_parentData) {}
}; };
/// Do nothing - default argument for post-visitor for tree traversal // Do nothing - default argument for post-visitor for tree traversal
template<typename NODE, typename DATA> template<typename NODE, typename DATA>
void no_op(const boost::shared_ptr<NODE>& node, const DATA& data) {} void no_op(const boost::shared_ptr<NODE>& node, const DATA& data) {}
// Internal node used in parallel traversal stack
template<typename NODE, typename DATA>
struct ParallelTraversalNode {
const boost::shared_ptr<NODE>& treeNode;
DATA myData;
ParallelTraversalNode(const boost::shared_ptr<NODE>& treeNode, const DATA& myData) :
treeNode(treeNode), myData(myData) {}
};
template<typename NODE, typename DATA, typename VISITOR_PRE, typename VISITOR_POST> template<typename NODE, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
class PreOrderTask : public tbb::task class PreOrderTask : public tbb::task
{ {
public: public:
const boost::shared_ptr<NODE>& treeNode; const boost::shared_ptr<NODE>& treeNode;
DATA& myData; DATA myData;
VISITOR_PRE& visitorPre; VISITOR_PRE& visitorPre;
VISITOR_POST& visitorPost; VISITOR_POST& visitorPost;
PreOrderTask(const boost::shared_ptr<NODE>& treeNode, DATA& myData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost) : int problemSizeThreshold;
treeNode(treeNode), myData(myData), visitorPre(visitorPre), visitorPost(visitorPost) {} PreOrderTask(const boost::shared_ptr<NODE>& treeNode, const DATA& myData,
VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost, int problemSizeThreshold) :
treeNode(treeNode), myData(myData), visitorPre(visitorPre), visitorPost(visitorPost),
problemSizeThreshold(problemSizeThreshold) {}
typedef ParallelTraversalNode<NODE, DATA> ParallelTraversalNode;
tbb::task* execute() tbb::task* execute()
{ {
// Set TBB ref count // Shared data
set_ref_count(1 + (int)treeNode->children.size()); int problemSize = 0;
// Create data and tasks for our children
std::vector<DATA> childData;
childData.reserve(treeNode->children.size());
std::vector<PreOrderTask*> tasks;
tasks.reserve(treeNode->children.size());
BOOST_FOREACH(const boost::shared_ptr<NODE>& child, treeNode->children)
{
childData.push_back(visitorPre(child, myData));
tasks.push_back(new(allocate_child()) PreOrderTask(child, childData.back(), visitorPre, visitorPost));
}
// Spawn tasks
BOOST_FOREACH(PreOrderTask* task, tasks)
spawn(*task);
// Wait for tasks to finish
wait_for_all();
// Now that the children are finished, run the post-order visitor //std::cout << "New task: " << std::endl;
(void) visitorPost(treeNode, myData); //BOOST_FOREACH(Key j, treeNode->keys)
// std::cout << j << " ";
//std::cout << std::endl;
// Process this node and its children
processNode(treeNode, myData, problemSize);
// Return NULL // Return NULL
return NULL; return NULL;
} }
void processNode(const boost::shared_ptr<NODE>& node, DATA& myData, int& problemSize)
{
tbb::task_list childTasks;
int nChildTasks = 0;
// Increment problem size for this node
problemSize += node->problemSize();
// Visit children until problem size exceeds a threshold, then spawn a new task
BOOST_FOREACH(const boost::shared_ptr<NODE>& child, node->children)
{
if(problemSize < problemSizeThreshold)
{
//std::cout << "problemSize = " << problemSize << std::endl;
//BOOST_FOREACH(Key j, child->keys)
// std::cout << j << " ";
//std::cout << std::endl;
// Process child sequentially (recursive call will increase problem size for children
DATA childData = visitorPre(child, myData);
processNode(child, childData, problemSize);
}
else
{
// Process child in a subtask
childTasks.push_back(*new(allocate_child())
PreOrderTask(child, visitorPre(child, myData), visitorPre, visitorPost, problemSizeThreshold));
++ nChildTasks;
}
}
// If we have child tasks, start subtasks and wait for them to complete
if(nChildTasks > 0) {
set_ref_count(1 + nChildTasks);
spawn(childTasks);
wait_for_all();
}
// Run the post-order visitor
(void) visitorPost(node, myData);
}
}; };
template<typename ROOTS, typename NODE, typename DATA, typename VISITOR_PRE, typename VISITOR_POST> template<typename ROOTS, typename NODE, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
@ -99,8 +144,11 @@ namespace gtsam {
DATA& myData; DATA& myData;
VISITOR_PRE& visitorPre; VISITOR_PRE& visitorPre;
VISITOR_POST& visitorPost; VISITOR_POST& visitorPost;
RootTask(const ROOTS& roots, DATA& myData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost) : int problemSizeThreshold;
roots(roots), myData(myData), visitorPre(visitorPre), visitorPost(visitorPost) {} RootTask(const ROOTS& roots, DATA& myData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost,
int problemSizeThreshold) :
roots(roots), myData(myData), visitorPre(visitorPre), visitorPost(visitorPost),
problemSizeThreshold(problemSizeThreshold) {}
tbb::task* execute() tbb::task* execute()
{ {
@ -108,14 +156,12 @@ namespace gtsam {
// Set TBB ref count // Set TBB ref count
set_ref_count(1 + (int)roots.size()); set_ref_count(1 + (int)roots.size());
// Create data and tasks for our children // Create data and tasks for our children
std::vector<DATA> rootData;
rootData.reserve(roots.size());
std::vector<PreOrderTask*> tasks; std::vector<PreOrderTask*> tasks;
tasks.reserve(roots.size()); tasks.reserve(roots.size());
BOOST_FOREACH(const boost::shared_ptr<NODE>& root, roots) BOOST_FOREACH(const boost::shared_ptr<NODE>& root, roots)
{ {
rootData.push_back(visitorPre(root, myData)); tasks.push_back(new(allocate_child())
tasks.push_back(new(allocate_child()) PreOrderTask(root, rootData.back(), visitorPre, visitorPost)); PreOrderTask(root, visitorPre(root, myData), visitorPre, visitorPost, problemSizeThreshold));
} }
// Spawn tasks // Spawn tasks
BOOST_FOREACH(PreOrderTask* task, tasks) BOOST_FOREACH(PreOrderTask* task, tasks)
@ -129,11 +175,19 @@ namespace gtsam {
template<typename NODE, typename ROOTS, typename DATA, typename VISITOR_PRE, typename VISITOR_POST> template<typename NODE, typename ROOTS, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
RootTask<ROOTS, NODE, DATA, VISITOR_PRE, VISITOR_POST>& RootTask<ROOTS, NODE, DATA, VISITOR_PRE, VISITOR_POST>&
CreateRootTask(const ROOTS& roots, DATA& rootData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost) CreateRootTask(const ROOTS& roots, DATA& rootData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost,
int problemSizeThreshold)
{ {
typedef RootTask<ROOTS, NODE, DATA, VISITOR_PRE, VISITOR_POST> RootTask; typedef RootTask<ROOTS, NODE, DATA, VISITOR_PRE, VISITOR_POST> RootTask;
return *new(tbb::task::allocate_root()) RootTask(roots, rootData, visitorPre, visitorPost); return *new(tbb::task::allocate_root()) RootTask(roots, rootData, visitorPre, visitorPost, problemSizeThreshold);
} }
/* ************************************************************************* */
//template<class NODE, typename DATA>
//struct ParallelDFSData {
// DATA myData;
// FastList<ParallelTraversalNode<NODE,DATA> >&
//};
} }
/** Traverse a forest depth-first with pre-order and post-order visits. /** Traverse a forest depth-first with pre-order and post-order visits.
@ -227,13 +281,15 @@ namespace gtsam {
* @param rootData The data to pass by reference to \c visitorPre when it is called on each * @param rootData The data to pass by reference to \c visitorPre when it is called on each
* root node. */ * root node. */
template<class FOREST, typename DATA, typename VISITOR_PRE, typename VISITOR_POST> template<class FOREST, typename DATA, typename VISITOR_PRE, typename VISITOR_POST>
void DepthFirstForestParallel(FOREST& forest, DATA& rootData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost) void DepthFirstForestParallel(FOREST& forest, DATA& rootData, VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost,
int problemSizeThreshold = 50)
{ {
// Typedefs // Typedefs
typedef typename FOREST::Node Node; typedef typename FOREST::Node Node;
typedef boost::shared_ptr<Node> sharedNode; typedef boost::shared_ptr<Node> sharedNode;
tbb::task::spawn_root_and_wait(CreateRootTask<Node>(forest.roots(), rootData, visitorPre, visitorPost)); tbb::task::spawn_root_and_wait(CreateRootTask<Node>(
forest.roots(), rootData, visitorPre, visitorPost, problemSizeThreshold));
} }