1 #ifndef SLA_CONCURRENCY_H
2 #define SLA_CONCURRENCY_H
3 
4 #include <tbb/spin_mutex.h>
5 #include <mutex>
6 #include <tbb/parallel_for.h>
7 #include <tbb/parallel_reduce.h>
8 
9 #include <algorithm>
10 #include <numeric>
11 
12 #include <libslic3r/libslic3r.h>
13 
14 namespace Slic3r {
15 namespace sla {
16 
17 // Set this to true to enable full parallelism in this module.
18 // Only the well tested parts will be concurrent if this is set to false.
19 const constexpr bool USE_FULL_CONCURRENCY = true;
20 
21 template<bool> struct _ccr {};
22 
23 template<> struct _ccr<true>
24 {
25     using SpinningMutex = tbb::spin_mutex;
26     using BlockingMutex = std::mutex;
27 
28     template<class Fn, class It>
loop_Slic3r::sla::_ccr29     static IteratorOnly<It, void> loop_(const tbb::blocked_range<It> &range, Fn &&fn)
30     {
31         for (auto &el : range) fn(el);
32     }
33 
34     template<class Fn, class I>
loop_Slic3r::sla::_ccr35     static IntegerOnly<I, void> loop_(const tbb::blocked_range<I> &range, Fn &&fn)
36     {
37         for (I i = range.begin(); i < range.end(); ++i) fn(i);
38     }
39 
40     template<class It, class Fn>
for_eachSlic3r::sla::_ccr41     static void for_each(It from, It to, Fn &&fn, size_t granularity = 1)
42     {
43         tbb::parallel_for(tbb::blocked_range{from, to, granularity},
44                           [&fn, from](const auto &range) {
45             loop_(range, std::forward<Fn>(fn));
46         });
47     }
48 
49     template<class I, class MergeFn, class T, class AccessFn>
reduceSlic3r::sla::_ccr50     static T reduce(I          from,
51                     I          to,
52                     const T   &init,
53                     MergeFn  &&mergefn,
54                     AccessFn &&access,
55                     size_t     granularity = 1
56                     )
57     {
58         return tbb::parallel_reduce(
59             tbb::blocked_range{from, to, granularity}, init,
60             [&](const auto &range, T subinit) {
61                 T acc = subinit;
62                 loop_(range, [&](auto &i) { acc = mergefn(acc, access(i)); });
63                 return acc;
64             },
65             std::forward<MergeFn>(mergefn));
66     }
67 
68     template<class I, class MergeFn, class T>
reduceSlic3r::sla::_ccr69     static IteratorOnly<I, T> reduce(I         from,
70                                      I         to,
71                                      const T & init,
72                                      MergeFn &&mergefn,
73                                      size_t    granularity = 1)
74     {
75         return reduce(
76             from, to, init, std::forward<MergeFn>(mergefn),
77             [](typename I::value_type &i) { return i; }, granularity);
78     }
79 };
80 
81 template<> struct _ccr<false>
82 {
83 private:
unlockSlic3r::sla::_ccr::_Mtx84     struct _Mtx { inline void lock() {} inline void unlock() {} };
85 
86 public:
87     using SpinningMutex = _Mtx;
88     using BlockingMutex = _Mtx;
89 
90     template<class Fn, class It>
loop_Slic3r::sla::_ccr91     static IteratorOnly<It, void> loop_(It from, It to, Fn &&fn)
92     {
93         for (auto it = from; it != to; ++it) fn(*it);
94     }
95 
96     template<class Fn, class I>
loop_Slic3r::sla::_ccr97     static IntegerOnly<I, void> loop_(I from, I to, Fn &&fn)
98     {
99         for (I i = from; i < to; ++i) fn(i);
100     }
101 
102     template<class It, class Fn>
for_eachSlic3r::sla::_ccr103     static void for_each(It   from,
104                          It   to,
105                          Fn &&fn,
106                          size_t /* ignore granularity */ = 1)
107     {
108         loop_(from, to, std::forward<Fn>(fn));
109     }
110 
111     template<class I, class MergeFn, class T, class AccessFn>
reduceSlic3r::sla::_ccr112     static T reduce(I         from,
113                     I         to,
114                     const T & init,
115                     MergeFn  &&mergefn,
116                     AccessFn &&access,
117                     size_t   /*granularity*/ = 1
118                     )
119     {
120         T acc = init;
121         loop_(from, to, [&](auto &i) { acc = mergefn(acc, access(i)); });
122         return acc;
123     }
124 
125     template<class I, class MergeFn, class T>
reduceSlic3r::sla::_ccr126     static IteratorOnly<I, T> reduce(I          from,
127                                      I          to,
128                                      const T   &init,
129                                      MergeFn  &&mergefn,
130                                      size_t     /*granularity*/ = 1
131                                      )
132     {
133         return reduce(from, to, init, std::forward<MergeFn>(mergefn),
134                       [](typename I::value_type &i) { return i; });
135     }
136 };
137 
138 using ccr = _ccr<USE_FULL_CONCURRENCY>;
139 using ccr_seq = _ccr<false>;
140 using ccr_par = _ccr<true>;
141 
142 }} // namespace Slic3r::sla
143 
144 #endif // SLACONCURRENCY_H
145