From f7b03701ae23f29bd57ae0c4e616dd764f1e7f86 Mon Sep 17 00:00:00 2001 From: Paul Heinzlreiter Date: Wed, 12 Oct 2016 08:40:03 +0200 Subject: [PATCH] * pthread tree build --- bh_tree_mpi/datastructures/BarnesHutTree.cpp | 8 +- bh_tree_mpi/datastructures/BarnesHutTree.hpp | 2 +- .../datastructures/BarnesHutTreeThreaded.cpp | 130 ++++++++++++++++++ .../datastructures/BarnesHutTreeThreaded.hpp | 36 +++++ bh_tree_mpi/datastructures/Node.hpp | 1 + .../ReadWriteLock.cpp | 0 .../ReadWriteLock.hpp | 0 bh_tree_mpi/datastructures/Tree.cpp | 6 + bh_tree_mpi/datastructures/Tree.hpp | 4 + bh_tree_mpi/simulation/PthreadSimulation.cpp | 6 + bh_tree_mpi/simulation/PthreadSimulation.hpp | 1 + 11 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp create mode 100644 bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp rename bh_tree_mpi/{simulation => datastructures}/ReadWriteLock.cpp (100%) rename bh_tree_mpi/{simulation => datastructures}/ReadWriteLock.hpp (100%) diff --git a/bh_tree_mpi/datastructures/BarnesHutTree.cpp b/bh_tree_mpi/datastructures/BarnesHutTree.cpp index bc8ea32..5849fce 100644 --- a/bh_tree_mpi/datastructures/BarnesHutTree.cpp +++ b/bh_tree_mpi/datastructures/BarnesHutTree.cpp @@ -84,10 +84,13 @@ namespace nbody { current->bodies.clear(); } - void BarnesHutTree::splitNode(Node* current) { - if (current->isSplitable()) { + bool BarnesHutTree::splitNode(Node* current) { + bool result = current->isSplitable(); + + if (result) { split(current); } + return result; } void BarnesHutTree::build(vector bodies, Box domain) { @@ -108,7 +111,6 @@ namespace nbody { //iterate over existing boxes and split if it contains too much bodies BarnesHutTree::splitSubtree(this->nodes->next); this->update(); - } void BarnesHutTree::build(vector bodies) { diff --git a/bh_tree_mpi/datastructures/BarnesHutTree.hpp b/bh_tree_mpi/datastructures/BarnesHutTree.hpp index 17b0363..85a81d3 100644 --- a/bh_tree_mpi/datastructures/BarnesHutTree.hpp +++ b/bh_tree_mpi/datastructures/BarnesHutTree.hpp @@ -12,7 +12,7 @@ namespace nbody { class BarnesHutTree : public Tree { protected: static vector splitBB(Node* node); - virtual void splitNode(Node* current); + static bool splitNode(Node* current); virtual void update(); static void split(Node* current); public: diff --git a/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp new file mode 100644 index 0000000..e4353b2 --- /dev/null +++ b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp @@ -0,0 +1,130 @@ +#include +#include +#include +#include "BarnesHutTreeThreaded.hpp" +#include "Node.hpp" +#include "PthreadSimulation.hpp" + +namespace nbody { + using namespace std; + + BarnesHutTreeThreaded::BarnesHutTreeThreaded(int parallelId) : BarnesHutTree(parallelId) { + pthread_mutex_init(&this->nodesToProcess.mutex, NULL); + } + + BarnesHutTreeThreaded::~BarnesHutTreeThreaded() { + pthread_mutex_destroy(&this->nodesToProcess.mutex); + } + + void BarnesHutTreeThreaded::addNodeToProcess(Node* node, NodesToProcess* store) { + pthread_mutex_lock(&store->mutex); + store->toProcess.push_back(node); + pthread_mutex_unlock(&store->mutex); + } + + Node* BarnesHutTreeThreaded::getNodeToProcess(NodesToProcess* store) { + Node* result; + + pthread_mutex_lock(&store->mutex); + if (store->toProcess.empty()) { + result = NULL; + } else { + result = store->toProcess.back(); + store->toProcess.pop_back(); + vector::iterator it = std::find(store->processing.begin(), store->processing.end(), pthread_self()); + if (it == store->processing.end()) { + store->processing.push_back(pthread_self()); + } + } + pthread_mutex_unlock(&store->mutex); + return result; + } + + void BarnesHutTreeThreaded::setNodeProcessingFinished(NodesToProcess* store) { + pthread_mutex_lock(&store->mutex); + vector::iterator it = std::find(store->processing.begin(), store->processing.end(), pthread_self()); + if (it != store->processing.end()) { + store->processing.erase(it); + } + pthread_mutex_unlock(&store->mutex); + } + + bool BarnesHutTreeThreaded::hasNodeProcessingFinished(NodesToProcess* store) { + bool finished; + + pthread_mutex_lock(&store->mutex); + finished = store->processing.empty() && store->toProcess.empty(); + pthread_mutex_unlock(&store->mutex); + return finished; + } + + void BarnesHutTreeThreaded::updateNode(Node* current) { + current->representative.id = ULONG_MAX; + current->representative.mass = 0.0; + current->representative.position[0] = 0.0; + current->representative.position[1] = 0.0; + current->representative.position[2] = 0.0; + for (unsigned int i = 0; i < current->bodies.size(); i++) { + current->representative.mass += current->bodies[i].mass; + for (int j = 0; j < 3; j++) { + current->representative.position[j] += current->bodies[i].position[j] * current->bodies[i].mass; + } + } + for (int j = 0; j < 3; j++) { + if (current->representative.mass > FLT_EPSILON) { + current->representative.position[j] /= current->representative.mass; + } else { + current->representative.position[j] = 0.0; + } + } + } + + void* BarnesHutTreeThreaded::build(void* data) { + NodesToProcess* toProcess = (NodesToProcess*) data; + + while (!BarnesHutTreeThreaded::hasNodeProcessingFinished(toProcess)) { + Node* current = BarnesHutTreeThreaded::getNodeToProcess(toProcess); + + if (current != NULL) { + updateNode(current); + if (BarnesHutTree::splitNode(current)) { + Node* child = current->next; + + while (child != NULL) { + BarnesHutTreeThreaded::addNodeToProcess(child, toProcess); + child = child->nextSibling; + } + } + } + } + return NULL; + } + + void BarnesHutTreeThreaded::clearNodesToProcess() { + this->nodesToProcess.processing.clear(); + this->nodesToProcess.toProcess.clear(); + } + + void BarnesHutTreeThreaded::build(vector bodies, Box domain) { + this->clean(); + if (bodies.empty()) return; + //insert root node + this->nodes->insertAfter(new Node(this)); + //assign bodies to root node + this->nodes->next->bodies = bodies; + //setup proper bounding box + this->nodes->next->bb = domain; + this->nodes->next->extendBBforBodies(); + this->nodes->next->extendBBtoCube(); + this->nodes->next->afterSubtree = this->nodes->next->next; + this->clearNodesToProcess(); + this->nodesToProcess.toProcess.push_back(this->nodes->next); + for (int i = 0; i < this->simulation->getNumberOfProcesses(); i++) { + pthread_create((&((PthreadSimulation*) this->simulation)->threads[i]), NULL, BarnesHutTreeThreaded::build, &this->nodesToProcess); + } + //iterate over existing boxes and split if it contains too much bodies + //BarnesHutTree::splitSubtree(this->nodes->next); + //this->update(); + } + +} diff --git a/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp new file mode 100644 index 0000000..317b223 --- /dev/null +++ b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp @@ -0,0 +1,36 @@ +#ifndef BARNES_HUT_TREE_THREADED_HPP +#define BARNES_HUT_TREE_THREADED_HPP + +#include +#include "BarnesHutTree.hpp" + +namespace nbody { + using namespace std; + + typedef struct _NodesToProcess { + pthread_mutex_t mutex; + vector toProcess; + vector processing; + } NodesToProcess; + + class BarnesHutTreeThreaded : public BarnesHutTree { + friend class PthreadSimulation; + protected: + NodesToProcess nodesToProcess; + + static void splitSubtree(Node* root); + static void* build(void* data); + static void updateNode(Node* current); + static void addNodeToProcess(Node* node, NodesToProcess* store); + static Node* getNodeToProcess(NodesToProcess* store); + static void setNodeProcessingFinished(NodesToProcess* store); + static bool hasNodeProcessingFinished(NodesToProcess* store); + virtual void clearNodesToProcess(); + public: + BarnesHutTreeThreaded(int parallelId); + virtual ~BarnesHutTreeThreaded(); + virtual void build(vector bodies, Box domain); + }; +} + +#endif diff --git a/bh_tree_mpi/datastructures/Node.hpp b/bh_tree_mpi/datastructures/Node.hpp index 39328b1..82ff6da 100644 --- a/bh_tree_mpi/datastructures/Node.hpp +++ b/bh_tree_mpi/datastructures/Node.hpp @@ -15,6 +15,7 @@ namespace nbody { class Node { friend class Tree; friend class BarnesHutTree; + friend class BarnesHutTreeThreaded; protected: Box bb; vector bodies; diff --git a/bh_tree_mpi/simulation/ReadWriteLock.cpp b/bh_tree_mpi/datastructures/ReadWriteLock.cpp similarity index 100% rename from bh_tree_mpi/simulation/ReadWriteLock.cpp rename to bh_tree_mpi/datastructures/ReadWriteLock.cpp diff --git a/bh_tree_mpi/simulation/ReadWriteLock.hpp b/bh_tree_mpi/datastructures/ReadWriteLock.hpp similarity index 100% rename from bh_tree_mpi/simulation/ReadWriteLock.hpp rename to bh_tree_mpi/datastructures/ReadWriteLock.hpp diff --git a/bh_tree_mpi/datastructures/Tree.cpp b/bh_tree_mpi/datastructures/Tree.cpp index 5fe2a16..782cba2 100644 --- a/bh_tree_mpi/datastructures/Tree.cpp +++ b/bh_tree_mpi/datastructures/Tree.cpp @@ -4,6 +4,7 @@ #include #include "Tree.hpp" #include "Node.hpp" +#include "Simulation.hpp" namespace nbody { using namespace std; @@ -13,6 +14,7 @@ namespace nbody { this->nodes = new Node(this); this->maxLeafBodies = 16; this->parallelId = parallelId; + this->simulation = NULL; } Tree::~Tree() { @@ -20,6 +22,10 @@ namespace nbody { delete this->nodes; } + void Tree::setSimulation(Simulation* simulation) { + this->simulation = simulation; + } + void Tree::clean() { //remove all nodes; refresh dummy first node while (this->nodes->next != this->nodes) { diff --git a/bh_tree_mpi/datastructures/Tree.hpp b/bh_tree_mpi/datastructures/Tree.hpp index 2d695c2..60beb7b 100644 --- a/bh_tree_mpi/datastructures/Tree.hpp +++ b/bh_tree_mpi/datastructures/Tree.hpp @@ -13,16 +13,20 @@ namespace nbody { using namespace std; class Node; + class Simulation; class Tree { friend class Node; + friend class PthreadSimulation; protected: Node* nodes; unsigned int maxLeafBodies; int parallelId; + Simulation* simulation; public: Tree(int parallelId); virtual ~Tree(); + virtual void setSimulation(Simulation* simulation); virtual void clean(); virtual void build(vector bodies) = 0; virtual void build(vector bodies, Box domain) = 0; diff --git a/bh_tree_mpi/simulation/PthreadSimulation.cpp b/bh_tree_mpi/simulation/PthreadSimulation.cpp index b0eb66e..46d3480 100644 --- a/bh_tree_mpi/simulation/PthreadSimulation.cpp +++ b/bh_tree_mpi/simulation/PthreadSimulation.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "BarnesHutTreeThreaded.hpp" namespace nbody { using namespace std; @@ -9,6 +10,7 @@ namespace nbody { } PthreadSimulation::~PthreadSimulation() { + delete this->tree; } void PthreadSimulation::initialize(string inputFile) { @@ -22,9 +24,13 @@ namespace nbody { this->threads.push_back(thread); } + this->tree = new BarnesHutTreeThreaded(-1); + this->tree->simulation = this; } void PthreadSimulation::cleanup() { + delete this->tree; + this->tree = NULL; pthread_exit(NULL); } diff --git a/bh_tree_mpi/simulation/PthreadSimulation.hpp b/bh_tree_mpi/simulation/PthreadSimulation.hpp index af35afc..8c0884e 100644 --- a/bh_tree_mpi/simulation/PthreadSimulation.hpp +++ b/bh_tree_mpi/simulation/PthreadSimulation.hpp @@ -8,6 +8,7 @@ namespace nbody { class PthreadSimulation : public Simulation { + friend class BarnesHutTreeThreaded; protected: vector threads; public: -- GitLab