VTK  9.3.20240907
vtkBatch.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
26#ifndef vtkBatch_h
27#define vtkBatch_h
28
29#include "vtkCommonCoreModule.h" // For export macro
30#include "vtkSMPTools.h"
31#include "vtkType.h"
32
33#include <algorithm>
34#include <functional>
35#include <vector>
36
37VTK_ABI_NAMESPACE_BEGIN
38//-----------------------------------------------------------------------------
39template <typename TBatchData>
41{
42 vtkBatch() = default;
43 ~vtkBatch() = default;
44
47 TBatchData Data;
48};
49
50//-----------------------------------------------------------------------------
51template <typename TBatchData>
53{
54private:
56 using vector = std::vector<vtkTBatch>;
57 using size_type = typename vector::size_type;
58 using reference = typename vector::reference;
59 using const_reference = typename vector::const_reference;
60 using iterator = typename vector::iterator;
61 using const_iterator = typename vector::const_iterator;
62
63public:
65 : BatchSize(0)
66 {
67 }
68 ~vtkBatches() = default;
69
73 void Initialize(vtkIdType numberOfElements, unsigned int batchSize = 1000)
74 {
75 this->BatchSize = batchSize;
76
77 const auto batchSizeSigned = static_cast<vtkIdType>(batchSize);
78 const auto numberOfBatches = ((numberOfElements - 1) / batchSizeSigned) + 1;
79 this->Batches.resize(static_cast<size_t>(numberOfBatches));
80 const auto lastBatchId = numberOfBatches - 1;
81
82 vtkSMPTools::For(0, numberOfBatches, [&](vtkIdType beginBatchId, vtkIdType endBatchId) {
83 vtkIdType endIdValues[2] = { -1, numberOfElements };
84 for (vtkIdType batchId = beginBatchId; batchId < endBatchId; ++batchId)
85 {
86 auto& batch = this->Batches[batchId];
87 batch.BeginId = batchId * batchSizeSigned;
88 endIdValues[0] = (batchId + 1) * batchSizeSigned;
89 batch.EndId = endIdValues[batchId == lastBatchId];
90 }
91 });
92 }
93
97 void TrimBatches(const std::function<bool(const vtkTBatch&)> shouldRemoveBatch)
98 {
99 const vtkIdType numberOfBatches = this->GetNumberOfBatches();
100 if (numberOfBatches == 0)
101 {
102 return;
103 }
104 const vtkIdType numberOfThreads =
105 std::min(static_cast<vtkIdType>(vtkSMPTools::GetEstimatedNumberOfThreads()), numberOfBatches);
106 const vtkIdType lastThreadId = numberOfThreads - 1;
107 const vtkIdType numberOfBatchesPerThread = numberOfBatches / numberOfThreads;
108
109 std::vector<vtkIdType> tlInterEndBatchId;
110 tlInterEndBatchId.resize(static_cast<size_t>(numberOfThreads));
111
112 // perform batch trimming of batch segments
113 vtkSMPTools::For(0, numberOfThreads, [&](vtkIdType beginThreadId, vtkIdType endThreadId) {
114 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
115 {
116 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
117 const vtkIdType endBatchId =
118 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
119 auto beginBatchIter = this->Batches.begin() + beginBatchId;
120 auto endBatchIter = this->Batches.begin() + endBatchId;
121 auto newEndBatchIter = std::remove_if(beginBatchIter, endBatchIter, shouldRemoveBatch);
122 tlInterEndBatchId[threadId] = beginBatchId + std::distance(beginBatchIter, newEndBatchIter);
123 }
124 });
125 // compute the new end batch ids;
126 std::vector<vtkIdType> tlNewEndBatchId;
127 tlNewEndBatchId.resize(static_cast<size_t>(numberOfThreads));
128 tlNewEndBatchId[0] = tlInterEndBatchId[0];
129 for (vtkIdType threadId = 1; threadId < numberOfThreads; ++threadId)
130 {
131 const vtkIdType beginOldBatchId = threadId * numberOfBatchesPerThread;
132 const auto& prevNewEndBatchId = tlNewEndBatchId[threadId - 1];
133 const vtkIdType distance = tlInterEndBatchId[threadId] - beginOldBatchId;
134 tlNewEndBatchId[threadId] = prevNewEndBatchId + distance;
135 std::move_backward(this->Batches.begin() + beginOldBatchId,
136 this->Batches.begin() + tlInterEndBatchId[threadId],
137 this->Batches.begin() + tlNewEndBatchId[threadId]);
138 }
139 this->Batches.erase(this->Batches.begin() + tlNewEndBatchId[lastThreadId], this->Batches.end());
140 }
141
154 {
155 const vtkIdType numberOfBatches = this->GetNumberOfBatches();
156 if (numberOfBatches == 0)
157 {
158 return TBatchData{};
159 }
160 const vtkIdType numberOfThreads =
161 std::min(static_cast<vtkIdType>(vtkSMPTools::GetEstimatedNumberOfThreads()), numberOfBatches);
162 const vtkIdType lastThreadId = numberOfThreads - 1;
163 const vtkIdType numberOfBatchesPerThread = numberOfBatches / numberOfThreads;
164
165 // calculate the thread local sums;
166 std::vector<TBatchData> tlSums;
167 tlSums.resize(static_cast<size_t>(numberOfThreads));
168
169 vtkSMPTools::For(0, numberOfThreads, [&](vtkIdType beginThreadId, vtkIdType endThreadId) {
170 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
171 {
172 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
173 const vtkIdType endBatchId =
174 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
175
176 auto& threadSum = tlSums[threadId];
177 for (vtkIdType batchId = beginBatchId; batchId < endBatchId; ++batchId)
178 {
179 threadSum += this->Batches[batchId].Data;
180 }
181 }
182 });
183
184 // calculate the global sum;
185 TBatchData globalSum;
186 for (const auto& threadSum : tlSums)
187 {
188 globalSum += threadSum;
189 }
190
191 // calculate the thread local offsets using the thread local sums
192 std::vector<TBatchData> tlOffsets;
193 tlOffsets.resize(static_cast<size_t>(numberOfThreads));
194 for (vtkIdType threadId = 1; threadId < numberOfThreads; ++threadId)
195 {
196 tlOffsets[threadId] = tlOffsets[threadId - 1] + tlSums[threadId - 1];
197 }
198
199 // convert the batch sums to offsets using the thread local offsets
200 vtkSMPTools::For(0, numberOfThreads, [&](vtkIdType beginThreadId, vtkIdType endThreadId) {
201 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
202 {
203 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
204 const vtkIdType endBatchId =
205 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
206
207 // store the first batch sum
208 auto lastBatchData = this->Batches[beginBatchId].Data;
209 // convert the first batch sum to an offset
210 this->Batches[beginBatchId].Data = tlOffsets[threadId];
211 for (vtkIdType batchId = beginBatchId + 1; batchId < endBatchId; ++batchId)
212 {
213 // store the current batch sum
214 const auto currentBatchData = this->Batches[batchId].Data;
215 // convert the current batch sum to an offset
216 this->Batches[batchId].Data = this->Batches[batchId - 1].Data + lastBatchData;
217 // store the current batch sum for the next iteration
218 lastBatchData = std::move(currentBatchData);
219 }
220 }
221 });
222
223 return globalSum;
224 }
225
229 vtkIdType GetNumberOfBatches() const { return static_cast<vtkIdType>(this->Batches.size()); }
230
234 unsigned int GetBatchSize() const { return this->BatchSize; }
235
237
240 reference operator[](size_type pos) noexcept { return this->Batches[pos]; }
241 const_reference operator[](size_type pos) const noexcept { return this->Batches[pos]; }
242 iterator begin() noexcept { return this->Batches.begin(); }
243 const_iterator begin() const noexcept { return this->Batches.begin(); }
244 const_iterator cbegin() const noexcept { return this->Batches.cbegin(); }
245 iterator end() noexcept { return this->Batches.end(); }
246 const_iterator end() const noexcept { return this->Batches.end(); }
247 const_iterator cend() const noexcept { return this->Batches.cend(); }
249
250private:
251 vector Batches;
252 unsigned int BatchSize;
253};
254VTK_ABI_NAMESPACE_END
255
256#endif // vtkBatch_h
257// VTK-HeaderTest-Exclude: vtkBatch.h
const_reference operator[](size_type pos) const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:241
vtkIdType GetNumberOfBatches() const
Get the number of batches.
Definition vtkBatch.h:229
const_iterator begin() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:243
unsigned int GetBatchSize() const
Get the batch size.
Definition vtkBatch.h:234
iterator begin() noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:242
void TrimBatches(const std::function< bool(const vtkTBatch &)> shouldRemoveBatch)
Remove batches that should be skipped.
Definition vtkBatch.h:97
iterator end() noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:245
const_iterator end() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:246
TBatchData BuildOffsetsAndGetGlobalSum()
Build offsets in place and returns the Global sum for a vtkBatch with Compact Batch Data.
Definition vtkBatch.h:153
~vtkBatches()=default
const_iterator cbegin() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:244
const_iterator cend() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:247
void Initialize(vtkIdType numberOfElements, unsigned int batchSize=1000)
Initialize the batches.
Definition vtkBatch.h:73
reference operator[](size_type pos) noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:240
static int GetEstimatedNumberOfThreads()
Get the estimated number of threads being used by the backend.
static void For(vtkIdType first, vtkIdType last, vtkIdType grain, Functor &f)
Execute a for operation in parallel.
vtkBatch is a simple structure that holds a begin and end id.
Definition vtkBatch.h:41
~vtkBatch()=default
TBatchData Data
Definition vtkBatch.h:47
vtkIdType EndId
Definition vtkBatch.h:46
vtkIdType BeginId
Definition vtkBatch.h:45
vtkBatch()=default
int vtkIdType
Definition vtkType.h:315