Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some more optimizations #503

Merged
merged 13 commits into from
Jul 24, 2023
3 changes: 2 additions & 1 deletion src/collider/src/collider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ SparseIndices Collider::Collisions(const VecDH<T>& queriesIn) const {
{thrust::pair<int*, int*>(nullptr, nullptr), counts.ptrD(),
nodeBBox_.ptrD(), internalChildren_.ptrD()}));
// compute start index for each query and total count
exclusive_scan(policy, counts.begin(), counts.end(), counts.begin());
exclusive_scan(policy, counts.begin(), counts.end(), counts.begin(), 0,
std::plus<int>());
SparseIndices queryTri(counts.back());
// actually recording collisions
for_each_n(policy, zip(queriesIn.cbegin(), countAt(0)), queriesIn.size(),
Expand Down
57 changes: 39 additions & 18 deletions src/polygon/src/polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@
#include "polygon.h"

#include <algorithm>
#if MANIFOLD_PAR == 'T'
#include <execution>
#endif
#include <list>
#include <map>
#if !__APPLE__
#include <memory_resource>
#endif
#include <queue>
#include <set>
#include <stack>
Expand Down Expand Up @@ -303,14 +309,25 @@ class Monotones {

private:
struct VertAdj;
typedef std::list<VertAdj>::iterator VertItr;
struct EdgePair;
typedef std::list<EdgePair>::iterator PairItr;
enum VertType { Start, WestSide, EastSide, Merge, End, Skip };
#if __APPLE__
typedef std::list<VertAdj>::iterator VertItr;
typedef std::list<EdgePair>::iterator PairItr;

std::list<VertAdj> monotones_; // sweep-line list of verts
std::list<EdgePair> activePairs_; // west to east list of monotone edge pairs
std::list<VertAdj> monotones_; // sweep-line list of verts
std::list<EdgePair> activePairs_; // west to east monotone edges
std::list<EdgePair> inactivePairs_; // completed monotones
#else
typedef std::pmr::list<VertAdj>::iterator VertItr;
typedef std::pmr::list<EdgePair>::iterator PairItr;

std::pmr::monotonic_buffer_resource mbr;
std::pmr::polymorphic_allocator<int> pa{&mbr};
std::pmr::list<VertAdj> monotones_{pa}; // sweep-line list of verts
std::pmr::list<EdgePair> activePairs_{pa}; // west to east monotone edges
std::pmr::list<EdgePair> inactivePairs_{pa}; // completed monotones
#endif
float precision_; // a triangle of this height or less is degenerate

/**
Expand Down Expand Up @@ -392,7 +409,7 @@ class Monotones {
class Triangulator {
public:
Triangulator(VertItr vert, float precision) : precision_(precision) {
reflex_chain_.push(vert);
reflex_chain_.push_back(vert);
other_side_ = vert;
}
int NumTriangles() const { return triangles_output_; }
Expand All @@ -407,14 +424,14 @@ class Monotones {
*/
void ProcessVert(const VertItr vi, bool onRight, bool last,
std::vector<glm::ivec3> &triangles) {
VertItr v_top = reflex_chain_.top();
VertItr v_top = reflex_chain_.back();
if (reflex_chain_.size() < 2) {
reflex_chain_.push(vi);
reflex_chain_.push_back(vi);
onRight_ = onRight;
return;
}
reflex_chain_.pop();
VertItr vj = reflex_chain_.top();
reflex_chain_.pop_back();
VertItr vj = reflex_chain_.back();
if (onRight_ == onRight && !last) {
// This only creates enough triangles to ensure the reflex chain is
// still reflex.
Expand All @@ -423,13 +440,13 @@ class Monotones {
while (ccw == (onRight_ ? 1 : -1) || ccw == 0) {
AddTriangle(triangles, vi, vj, v_top);
v_top = vj;
reflex_chain_.pop();
reflex_chain_.pop_back();
if (reflex_chain_.empty()) break;
vj = reflex_chain_.top();
vj = reflex_chain_.back();
ccw = CCW(vi->pos, vj->pos, v_top->pos, precision_);
}
reflex_chain_.push(v_top);
reflex_chain_.push(vi);
reflex_chain_.push_back(v_top);
reflex_chain_.push_back(vi);
} else {
// This branch empties the reflex chain and switches sides. It must be
// used for the last point, as it will output all the triangles
Expand All @@ -438,19 +455,19 @@ class Monotones {
onRight_ = !onRight_;
VertItr v_last = v_top;
while (!reflex_chain_.empty()) {
vj = reflex_chain_.top();
vj = reflex_chain_.back();
AddTriangle(triangles, vi, v_last, vj);
v_last = vj;
reflex_chain_.pop();
reflex_chain_.pop_back();
}
reflex_chain_.push(v_top);
reflex_chain_.push(vi);
reflex_chain_.push_back(v_top);
reflex_chain_.push_back(vi);
other_side_ = v_top;
}
}

private:
std::stack<VertItr> reflex_chain_;
std::vector<VertItr> reflex_chain_;
VertItr other_side_; // The end vertex across from the reflex chain
bool onRight_; // The side the reflex chain is on
int triangles_output_ = 0;
Expand Down Expand Up @@ -784,7 +801,11 @@ class Monotones {
starts.push_back(v);
}
}
#if MANIFOLD_PAR == 'T' && !(__APPLE__)
std::sort(std::execution::par_unseq, starts.begin(), starts.end(), cmp);
#else
std::sort(starts.begin(), starts.end(), cmp);
#endif

std::vector<VertItr> skipped;
VertItr insertAt = monotones_.begin();
Expand Down
101 changes: 83 additions & 18 deletions src/utilities/include/par.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#define MANIFOLD_PAR_NS omp
#elif MANIFOLD_PAR == 'T'
#include <thrust/system/tbb/execution_policy.h>

#include <algorithm>
#include <execution>
#define MANIFOLD_PAR_NS tbb
#else
#define MANIFOLD_PAR_NS cpp
Expand Down Expand Up @@ -136,43 +139,105 @@ inline ExecutionPolicy autoPolicy(int size) {
thrust::NAME(thrust::cpp::par, args...); \
}

#if MANIFOLD_PAR == 'T' && !(__APPLE__)
// sometimes stl variant is faster
#define STL_DYNAMIC_BACKEND(NAME, RET) \
template <typename Ret = RET, typename... Args> \
Ret NAME(ExecutionPolicy policy, Args... args) { \
switch (policy) { \
case ExecutionPolicy::ParUnseq: \
case ExecutionPolicy::Par: \
return std::NAME(std::execution::par_unseq, args...); \
case ExecutionPolicy::Seq: \
break; \
} \
return std::NAME(args...); \
}
#define STL_DYNAMIC_BACKEND_VOID(NAME) \
template <typename... Args> \
void NAME(ExecutionPolicy policy, Args... args) { \
switch (policy) { \
case ExecutionPolicy::ParUnseq: \
case ExecutionPolicy::Par: \
std::NAME(std::execution::par_unseq, args...); \
break; \
case ExecutionPolicy::Seq: \
std::NAME(args...); \
break; \
} \
}

template <typename... Args>
void exclusive_scan(ExecutionPolicy policy, Args... args) {
// https://github.com/llvm/llvm-project/issues/59810
std::exclusive_scan(args...);
}
template <typename DerivedPolicy, typename InputIterator1,
typename InputIterator2, typename OutputIterator, typename Predicate>
OutputIterator copy_if(ExecutionPolicy policy, InputIterator1 first,
InputIterator1 last, InputIterator2 stencil,
OutputIterator result, Predicate pred) {
if (policy == ExecutionPolicy::Seq)
return thrust::copy_if(thrust::cpp::par, first, last, stencil, result,
pred);
else
// note: this is not a typo, see
// https://github.com/NVIDIA/thrust/issues/1977
return thrust::copy_if(first, last, stencil, result, pred);
}
template <typename DerivedPolicy, typename InputIterator1,
typename OutputIterator, typename Predicate>
OutputIterator copy_if(ExecutionPolicy policy, InputIterator1 first,
InputIterator1 last, OutputIterator result,
Predicate pred) {
if (policy == ExecutionPolicy::Seq)
return std::copy_if(first, last, result, pred);
else
return std::copy_if(std::execution::par_unseq, first, last, result, pred);
}
#else
#define STL_DYNAMIC_BACKEND(NAME, RET) THRUST_DYNAMIC_BACKEND(NAME, RET)
#define STL_DYNAMIC_BACKEND_VOID(NAME) THRUST_DYNAMIC_BACKEND_VOID(NAME)

THRUST_DYNAMIC_BACKEND_VOID(exclusive_scan)
THRUST_DYNAMIC_BACKEND(copy_if, void)
#endif

THRUST_DYNAMIC_BACKEND_HOST_VOID(for_each)
THRUST_DYNAMIC_BACKEND_HOST_VOID(for_each_n)

THRUST_DYNAMIC_BACKEND_VOID(gather)
THRUST_DYNAMIC_BACKEND_VOID(scatter)
THRUST_DYNAMIC_BACKEND_VOID(for_each)
THRUST_DYNAMIC_BACKEND_VOID(for_each_n)
THRUST_DYNAMIC_BACKEND_VOID(sort)
THRUST_DYNAMIC_BACKEND_VOID(stable_sort)
THRUST_DYNAMIC_BACKEND_VOID(fill)
THRUST_DYNAMIC_BACKEND_VOID(sequence)
THRUST_DYNAMIC_BACKEND_VOID(sort_by_key)
THRUST_DYNAMIC_BACKEND_VOID(stable_sort_by_key)
THRUST_DYNAMIC_BACKEND_VOID(copy)
THRUST_DYNAMIC_BACKEND_VOID(transform)
THRUST_DYNAMIC_BACKEND_VOID(inclusive_scan)
THRUST_DYNAMIC_BACKEND_VOID(exclusive_scan)
THRUST_DYNAMIC_BACKEND_VOID(uninitialized_fill)
THRUST_DYNAMIC_BACKEND_VOID(uninitialized_copy)
THRUST_DYNAMIC_BACKEND_VOID(stable_sort)
THRUST_DYNAMIC_BACKEND_VOID(fill)
THRUST_DYNAMIC_BACKEND_VOID(copy)
THRUST_DYNAMIC_BACKEND_VOID(inclusive_scan)
THRUST_DYNAMIC_BACKEND_VOID(copy_n)
STL_DYNAMIC_BACKEND_VOID(sort)

THRUST_DYNAMIC_BACKEND(all_of, bool)
THRUST_DYNAMIC_BACKEND(is_sorted, bool)
THRUST_DYNAMIC_BACKEND(reduce, void)
THRUST_DYNAMIC_BACKEND(count_if, int)
THRUST_DYNAMIC_BACKEND(binary_search, bool)
// void implies that the user have to specify the return type in the template
// argument, as we are unable to deduce it
THRUST_DYNAMIC_BACKEND(transform_reduce, void)
THRUST_DYNAMIC_BACKEND(gather_if, void)
THRUST_DYNAMIC_BACKEND(reduce_by_key, void)
THRUST_DYNAMIC_BACKEND(lower_bound, void)
THRUST_DYNAMIC_BACKEND(remove, void)
THRUST_DYNAMIC_BACKEND(copy_if, void)
THRUST_DYNAMIC_BACKEND(remove_if, void)
THRUST_DYNAMIC_BACKEND(unique, void)
THRUST_DYNAMIC_BACKEND(find, void)
THRUST_DYNAMIC_BACKEND(find_if, void)
THRUST_DYNAMIC_BACKEND(reduce_by_key, void)
THRUST_DYNAMIC_BACKEND(transform_reduce, void)
THRUST_DYNAMIC_BACKEND(lower_bound, void)
THRUST_DYNAMIC_BACKEND(gather_if, void)
THRUST_DYNAMIC_BACKEND(all_of, bool)
THRUST_DYNAMIC_BACKEND(is_sorted, bool)
THRUST_DYNAMIC_BACKEND(reduce, void)
THRUST_DYNAMIC_BACKEND(count_if, int)
THRUST_DYNAMIC_BACKEND(binary_search, bool)
STL_DYNAMIC_BACKEND(remove_if, void)
STL_DYNAMIC_BACKEND(unique, void)

} // namespace manifold