OpenVDB
13.0.0
Toggle main menu visibility
Loading...
Searching...
No Matches
Reduce.h
Go to the documentation of this file.
1
// Copyright Contributors to the OpenVDB Project
2
// SPDX-License-Identifier: Apache-2.0
3
4
/*!
5
\file nanovdb/util/Reduce.h
6
7
\author Ken Museth
8
9
\date March 4, 2021
10
11
\brief A unified wrapper for tbb::parallel_reduce and a naive std::future analog
12
*/
13
14
#ifndef NANOVDB_UTIL_REDUCE_H_HAS_BEEN_INCLUDED
15
#define NANOVDB_UTIL_REDUCE_H_HAS_BEEN_INCLUDED
16
17
#include <
nanovdb/util/Range.h
>
// for util::Range1D
18
19
#ifdef NANOVDB_USE_TBB
20
#include <tbb/parallel_reduce.h>
21
#else
22
#include <thread>
23
#include <future>
24
#include <vector>
25
#endif
26
27
namespace
nanovdb
{
28
29
namespace
util
{
30
31
/// @return reduction
32
///
33
/// @param range RangeT can be Range<dim,T>, CoordBBox, tbb::blocked_range, blocked_range2D, or blocked_range3D.
34
/// @param identity initial value
35
/// @param func functor with signature T FuncT::operator()(const RangeT& range, const T& a) const
36
/// @param join functor with the signature T JoinT::operator()(const T& a, const T& b) const
37
/// @code
38
/// std::vector<int> array(100, 1);
39
/// auto func = [&array](auto &r, int a){for (auto i=r.begin(); i!=r.end(); ++i) a+=array[i]; return a;};
40
/// int sum = reduce(array, 0, func, [](int a, int b){return a + b;});
41
/// @endcode
42
template
<
typename
RangeT,
typename
T,
typename
FuncT,
typename
JoinT>
43
inline
T
reduce
(RangeT range,
const
T& identity,
const
FuncT &func,
const
JoinT &join)
44
{
45
if
(range.empty())
return
identity;
46
#ifdef NANOVDB_USE_TBB
47
return
tbb::parallel_reduce(range, identity, func, join);
48
#else
// naive and likely slow alternative based on std::future
49
if
(
const
size_t
threadCount = std::thread::hardware_concurrency()>>1) {
50
std::vector<RangeT> rangePool{ range };
51
while
(rangePool.size() < threadCount) {
52
const
size_t
oldSize = rangePool.size();
53
for
(
size_t
i = 0; i < oldSize && rangePool.size() < threadCount; ++i) {
54
auto
&r = rangePool[i];
55
if
(r.is_divisible()) rangePool.push_back(RangeT(r,
Split
()));
56
}
57
if
(rangePool.size() == oldSize)
break
;
// none of the ranges were divided so stop
58
}
59
std::vector< std::future<T> > futurePool;
60
for
(
auto
&r : rangePool) {
61
auto
task = std::async(std::launch::async, [&](){
return
func(r, identity);});
62
futurePool.push_back( std::move(task) );
// launch tasks
63
}
64
T result = identity;
65
for
(
auto
&f : futurePool) {
66
result = join(result, f.get());
// join results
67
}
68
return
result;
69
}
else
{
// serial
70
return
static_cast<
T
>
(func(range, identity));
71
}
72
#endif
73
return
identity;
// should never happen
74
}
75
76
/// @brief Simple wrapper to the function defined above
77
template
<
typename
T,
typename
FuncT,
typename
JoinT>
78
inline
T
reduce
(
size_t
begin,
size_t
end,
size_t
grainSize,
const
T& identity,
const
FuncT& func,
const
JoinT& join)
79
{
80
Range1D
range(begin, end, grainSize);
81
return
reduce
( range, identity, func, join );
82
}
83
84
/// @brief Simple wrapper that works with std::containers
85
template
<
template
<
typename
...>
class
ContainerT,
typename
... ArgT,
typename
T,
typename
FuncT,
typename
JoinT >
86
inline
T
reduce
(
const
ContainerT<ArgT...> &c,
const
T& identity,
const
FuncT& func,
const
JoinT& join)
87
{
88
Range1D
range(0, c.size(), 1);
89
return
reduce
( range, identity, func, join );
90
91
}
92
93
/// @brief Simple wrapper that works with std::containers
94
template
<
template
<
typename
...>
class
ContainerT,
typename
... ArgT,
typename
T,
typename
FuncT,
typename
JoinT >
95
inline
T
reduce
(
const
ContainerT<ArgT...> &c,
size_t
grainSize,
const
T& identity,
const
FuncT& func,
const
JoinT& join)
96
{
97
Range1D
range(0, c.size(), grainSize);
98
return
reduce
( range, identity, func, join );
99
}
100
101
}
// namespace util
102
103
/// @brief Simple wrapper to the function defined above
104
template
<
typename
T,
typename
FuncT,
typename
JoinT>
105
[[deprecated(
"Use nanovdb::util::reduce instead"
)]]
106
inline
T
reduce
(
size_t
begin,
size_t
end,
size_t
grainSize,
const
T& identity,
const
FuncT& func,
const
JoinT& join)
107
{
108
util::Range1D
range(begin, end, grainSize);
109
return
util::reduce
( range, identity, func, join );
110
}
111
112
/// @brief Simple wrapper that works with std::containers
113
template
<
template
<
typename
...>
class
ContainerT,
typename
... ArgT,
typename
T,
typename
FuncT,
typename
JoinT >
114
[[deprecated(
"Use nanovdb::util::reduce instead"
)]]
115
inline
T
reduce
(
const
ContainerT<ArgT...> &c,
const
T& identity,
const
FuncT& func,
const
JoinT& join)
116
{
117
util::Range1D
range(0, c.size(), 1);
118
return
util::reduce
( range, identity, func, join );
119
120
}
121
122
/// @brief Simple wrapper that works with std::containers
123
template
<
template
<
typename
...>
class
ContainerT,
typename
... ArgT,
typename
T,
typename
FuncT,
typename
JoinT >
124
[[deprecated(
"Use nanovdb::util::reduce instead"
)]]
125
T
reduce
(
const
ContainerT<ArgT...> &c,
size_t
grainSize,
const
T& identity,
const
FuncT& func,
const
JoinT& join)
126
{
127
util::Range1D
range(0, c.size(), grainSize);
128
return
util::reduce
( range, identity, func, join );
129
}
130
131
}
// namespace nanovdb
132
133
#endif
// NANOVDB_UTIL_REDUCE_H_HAS_BEEN_INCLUDED
Range.h
Custom Range class that is compatible with the tbb::blocked_range classes.
nanovdb::util::Split
Definition
Range.h:28
nanovdb::util
Definition
ForEach.h:29
nanovdb::util::reduce
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition
Reduce.h:43
nanovdb::util::Range1D
Range< 1, size_t > Range1D
Definition
Range.h:33
nanovdb
Definition
GridHandle.h:27
nanovdb::reduce
T reduce(size_t begin, size_t end, size_t grainSize, const T &identity, const FuncT &func, const JoinT &join)
Simple wrapper to the function defined above.
Definition
Reduce.h:106
nanovdb
util
Reduce.h
Generated by
1.18.0