Optimization of triangle mesh slicing: scalable_allocator and hashing

of shared mutexes.
This commit is contained in:
Vojtech Bubnik 2023-05-02 15:53:08 +02:00
parent 0836b06c73
commit 31a5daa5e4

View file

@ -15,6 +15,9 @@
#include <boost/log/trivial.hpp>
#include <tbb/parallel_for.h>
#include <tbb/scalable_allocator.h>
#include <ankerl/unordered_dense.h>
#ifndef NDEBUG
// #define EXPENSIVE_DEBUG_CHECKS
@ -139,7 +142,7 @@ public:
#endif
};
using IntersectionLines = std::vector<IntersectionLine>;
using IntersectionLines = std::vector<IntersectionLine, tbb::scalable_allocator<IntersectionLine>>;
enum class FacetSliceType {
NoSlice = 0,
@ -351,6 +354,21 @@ inline FacetSliceType slice_facet(
return FacetSliceType::NoSlice;
}
class LinesMutexes {
public:
std::mutex& operator()(size_t slice_id) {
ankerl::unordered_dense::hash<size_t> hash;
return m_mutexes[hash(slice_id) % m_mutexes.size()].mutex;
}
private:
struct CacheLineAlignedMutex
{
alignas(std::hardware_destructive_interference_size) std::mutex mutex;
};
std::array<CacheLineAlignedMutex, 64> m_mutexes;
};
template<typename TransformVertex>
void slice_facet_at_zs(
// Scaled or unscaled vertices. transform_vertex_fn may scale zs.
@ -361,7 +379,7 @@ void slice_facet_at_zs(
// Scaled or unscaled zs. If vertices have their zs scaled or transform_vertex_fn scales them, then zs have to be scaled as well.
const std::vector<float> &zs,
std::vector<IntersectionLines> &lines,
std::array<std::mutex, 64> &lines_mutex)
LinesMutexes &lines_mutex)
{
stl_vertex vertices[3] { transform_vertex_fn(mesh_vertices[indices(0)]), transform_vertex_fn(mesh_vertices[indices(1)]), transform_vertex_fn(mesh_vertices[indices(2)]) };
@ -380,7 +398,7 @@ void slice_facet_at_zs(
if (min_z != max_z && slice_facet(*it, vertices, indices, edge_ids, idx_vertex_lowest, false, il) == FacetSliceType::Slicing) {
assert(il.edge_type != IntersectionLine::FacetEdgeType::Horizontal);
size_t slice_id = it - zs.begin();
boost::lock_guard<std::mutex> l(lines_mutex[slice_id % lines_mutex.size()]);
boost::lock_guard<std::mutex> l(lines_mutex(slice_id));
lines[slice_id].emplace_back(il);
}
}
@ -395,8 +413,8 @@ static inline std::vector<IntersectionLines> slice_make_lines(
const std::vector<float> &zs,
const ThrowOnCancel throw_on_cancel_fn)
{
std::vector<IntersectionLines> lines(zs.size(), IntersectionLines());
std::array<std::mutex, 64> lines_mutex;
std::vector<IntersectionLines> lines(zs.size(), IntersectionLines{});
LinesMutexes lines_mutex;
tbb::parallel_for(
tbb::blocked_range<int>(0, int(indices.size())),
[&vertices, &transform_vertex_fn, &indices, &face_edge_ids, &zs, &lines, &lines_mutex, throw_on_cancel_fn](const tbb::blocked_range<int> &range) {
@ -475,7 +493,7 @@ void slice_facet_with_slabs(
const int num_edges,
const std::vector<float> &zs,
SlabLines &lines,
std::array<std::mutex, 64> &lines_mutex)
LinesMutexes &lines_mutex)
{
const stl_triangle_vertex_indices &indices = mesh_triangles[facet_idx];
stl_vertex vertices[3] { mesh_vertices[indices(0)], mesh_vertices[indices(1)], mesh_vertices[indices(2)] };
@ -494,7 +512,7 @@ void slice_facet_with_slabs(
auto emit_slab_edge = [&lines, &lines_mutex](IntersectionLine il, size_t slab_id, bool reverse) {
if (reverse)
il.reverse();
boost::lock_guard<std::mutex> l(lines_mutex[(slab_id + lines_mutex.size() / 2) % lines_mutex.size()]);
boost::lock_guard<std::mutex> l(lines_mutex(slab_id));
lines.between_slices[slab_id].emplace_back(il);
};
@ -530,7 +548,7 @@ void slice_facet_with_slabs(
};
// Don't flip the FacetEdgeType::Top edge, it will be flipped when chaining.
// if (! ProjectionFromTop) il.reverse();
boost::lock_guard<std::mutex> l(lines_mutex[line_id % lines_mutex.size()]);
boost::lock_guard<std::mutex> l(lines_mutex(line_id));
lines.at_slice[line_id].emplace_back(il);
}
} else {
@ -649,7 +667,7 @@ void slice_facet_with_slabs(
if (! ProjectionFromTop)
il.reverse();
size_t line_id = it - zs.begin();
boost::lock_guard<std::mutex> l(lines_mutex[line_id % lines_mutex.size()]);
boost::lock_guard<std::mutex> l(lines_mutex(line_id));
lines.at_slice[line_id].emplace_back(il);
}
}
@ -804,8 +822,8 @@ inline std::pair<SlabLines, SlabLines> slice_slabs_make_lines(
std::pair<SlabLines, SlabLines> out;
SlabLines &lines_top = out.first;
SlabLines &lines_bottom = out.second;
std::array<std::mutex, 64> lines_mutex_top;
std::array<std::mutex, 64> lines_mutex_bottom;
LinesMutexes lines_mutex_top;
LinesMutexes lines_mutex_bottom;
if (top) {
lines_top.at_slice.assign(zs.size(), IntersectionLines());
@ -1540,7 +1558,7 @@ static std::vector<Polygons> make_slab_loops(
}
// Used to cut the mesh into two halves.
static ExPolygons make_expolygons_simple(std::vector<IntersectionLine> &lines)
static ExPolygons make_expolygons_simple(IntersectionLines &lines)
{
ExPolygons slices;
Polygons holes;