MCPcopy Create free account
hub / github.com/apache/arrow / SumArray

Function SumArray

cpp/src/arrow/compute/kernels/aggregate_internal.h:159–232  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

157template <typename ValueType, typename SumType, SimdLevel::type SimdLevel,
158 typename ValueFunc>
159enable_if_t<std::is_floating_point<SumType>::value, SumType> SumArray(
160 const ArraySpan& data, ValueFunc&& func) {
161 using arrow::internal::VisitSetBitRunsVoid;
162
163 const int64_t data_size = data.length - data.GetNullCount();
164 if (data_size == 0) {
165 return 0;
166 }
167
168 // number of inputs to accumulate before merging with another block
169 constexpr int kBlockSize = 16; // same as numpy
170 // levels (tree depth) = ceil(log2(len)) + 1, a bit larger than necessary
171 const int levels = bit_util::Log2(static_cast<uint64_t>(data_size)) + 1;
172 // temporary summation per level
173 std::vector<SumType> sum(levels);
174 // whether two summations are ready and should be reduced to upper level
175 // one bit for each level, bit0 -> level0, ...
176 uint64_t mask = 0;
177 // level of root node holding the final summation
178 int root_level = 0;
179
180 // reduce summation of one block (may be smaller than kBlockSize) from leaf node
181 // continue reducing to upper level if two summations are ready for non-leaf node
182 // (capture `levels` by value because of ARROW-17567)
183 auto reduce = [&, levels](SumType block_sum) {
184 int cur_level = 0;
185 uint64_t cur_level_mask = 1ULL;
186 sum[cur_level] += block_sum;
187 mask ^= cur_level_mask;
188 while ((mask & cur_level_mask) == 0) {
189 block_sum = sum[cur_level];
190 sum[cur_level] = 0;
191 ++cur_level;
192 DCHECK_LT(cur_level, levels);
193 cur_level_mask <<= 1;
194 sum[cur_level] += block_sum;
195 mask ^= cur_level_mask;
196 }
197 root_level = std::max(root_level, cur_level);
198 };
199
200 const ValueType* values = data.GetValues<ValueType>(1);
201 VisitSetBitRunsVoid(data.buffers[0].data, data.offset, data.length,
202 [&](int64_t pos, int64_t len) {
203 const ValueType* v = &values[pos];
204 // unsigned division by constant is cheaper than signed one
205 const uint64_t blocks = static_cast<uint64_t>(len) / kBlockSize;
206 const uint64_t remains = static_cast<uint64_t>(len) % kBlockSize;
207
208 for (uint64_t i = 0; i < blocks; ++i) {
209 SumType block_sum = 0;
210 for (int j = 0; j < kBlockSize; ++j) {
211 block_sum += func(v[j]);
212 }
213 reduce(block_sum);
214 v += kBlockSize;
215 }
216

Callers

nothing calls this directly

Calls 4

VisitSetBitRunsVoidFunction · 0.85
GetNullCountMethod · 0.80
Log2Class · 0.70
funcFunction · 0.50

Tested by

no test coverage detected