VTK  9.4.20241222
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,
83 [&](vtkIdType beginBatchId, vtkIdType endBatchId)
84 {
85 vtkIdType endIdValues[2] = { -1, numberOfElements };
86 for (vtkIdType batchId = beginBatchId; batchId < endBatchId; ++batchId)
87 {
88 auto& batch = this->Batches[batchId];
89 batch.BeginId = batchId * batchSizeSigned;
90 endIdValues[0] = (batchId + 1) * batchSizeSigned;
91 batch.EndId = endIdValues[batchId == lastBatchId];
92 }
93 });
94 }
95
99 void TrimBatches(const std::function<bool(const vtkTBatch&)> shouldRemoveBatch)
100 {
101 const vtkIdType numberOfBatches = this->GetNumberOfBatches();
102 if (numberOfBatches == 0)
103 {
104 return;
105 }
106 const vtkIdType numberOfThreads =
107 std::min(static_cast<vtkIdType>(vtkSMPTools::GetEstimatedNumberOfThreads()), numberOfBatches);
108 const vtkIdType lastThreadId = numberOfThreads - 1;
109 const vtkIdType numberOfBatchesPerThread = numberOfBatches / numberOfThreads;
110
111 std::vector<vtkIdType> tlInterEndBatchId;
112 tlInterEndBatchId.resize(static_cast<size_t>(numberOfThreads));
113
114 // perform batch trimming of batch segments
115 vtkSMPTools::For(0, numberOfThreads,
116 [&](vtkIdType beginThreadId, vtkIdType endThreadId)
117 {
118 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
119 {
120 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
121 const vtkIdType endBatchId =
122 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
123 auto beginBatchIter = this->Batches.begin() + beginBatchId;
124 auto endBatchIter = this->Batches.begin() + endBatchId;
125 auto newEndBatchIter = std::remove_if(beginBatchIter, endBatchIter, shouldRemoveBatch);
126 tlInterEndBatchId[threadId] =
127 beginBatchId + std::distance(beginBatchIter, newEndBatchIter);
128 }
129 });
130 // compute the new end batch ids;
131 std::vector<vtkIdType> tlNewEndBatchId;
132 tlNewEndBatchId.resize(static_cast<size_t>(numberOfThreads));
133 tlNewEndBatchId[0] = tlInterEndBatchId[0];
134 for (vtkIdType threadId = 1; threadId < numberOfThreads; ++threadId)
135 {
136 const vtkIdType beginOldBatchId = threadId * numberOfBatchesPerThread;
137 const auto& prevNewEndBatchId = tlNewEndBatchId[threadId - 1];
138 const vtkIdType distance = tlInterEndBatchId[threadId] - beginOldBatchId;
139 tlNewEndBatchId[threadId] = prevNewEndBatchId + distance;
140 std::move_backward(this->Batches.begin() + beginOldBatchId,
141 this->Batches.begin() + tlInterEndBatchId[threadId],
142 this->Batches.begin() + tlNewEndBatchId[threadId]);
143 }
144 this->Batches.erase(this->Batches.begin() + tlNewEndBatchId[lastThreadId], this->Batches.end());
145 }
146
159 {
160 const vtkIdType numberOfBatches = this->GetNumberOfBatches();
161 if (numberOfBatches == 0)
162 {
163 return TBatchData{};
164 }
165 const vtkIdType numberOfThreads =
166 std::min(static_cast<vtkIdType>(vtkSMPTools::GetEstimatedNumberOfThreads()), numberOfBatches);
167 const vtkIdType lastThreadId = numberOfThreads - 1;
168 const vtkIdType numberOfBatchesPerThread = numberOfBatches / numberOfThreads;
169
170 // calculate the thread local sums;
171 std::vector<TBatchData> tlSums;
172 tlSums.resize(static_cast<size_t>(numberOfThreads));
173
174 vtkSMPTools::For(0, numberOfThreads,
175 [&](vtkIdType beginThreadId, vtkIdType endThreadId)
176 {
177 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
178 {
179 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
180 const vtkIdType endBatchId =
181 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
182
183 auto& threadSum = tlSums[threadId];
184 for (vtkIdType batchId = beginBatchId; batchId < endBatchId; ++batchId)
185 {
186 threadSum += this->Batches[batchId].Data;
187 }
188 }
189 });
190
191 // calculate the global sum;
192 TBatchData globalSum;
193 for (const auto& threadSum : tlSums)
194 {
195 globalSum += threadSum;
196 }
197
198 // calculate the thread local offsets using the thread local sums
199 std::vector<TBatchData> tlOffsets;
200 tlOffsets.resize(static_cast<size_t>(numberOfThreads));
201 for (vtkIdType threadId = 1; threadId < numberOfThreads; ++threadId)
202 {
203 tlOffsets[threadId] = tlOffsets[threadId - 1] + tlSums[threadId - 1];
204 }
205
206 // convert the batch sums to offsets using the thread local offsets
207 vtkSMPTools::For(0, numberOfThreads,
208 [&](vtkIdType beginThreadId, vtkIdType endThreadId)
209 {
210 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
211 {
212 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
213 const vtkIdType endBatchId =
214 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
215
216 // store the first batch sum
217 auto lastBatchData = this->Batches[beginBatchId].Data;
218 // convert the first batch sum to an offset
219 this->Batches[beginBatchId].Data = tlOffsets[threadId];
220 for (vtkIdType batchId = beginBatchId + 1; batchId < endBatchId; ++batchId)
221 {
222 // store the current batch sum
223 const auto currentBatchData = this->Batches[batchId].Data;
224 // convert the current batch sum to an offset
225 this->Batches[batchId].Data = this->Batches[batchId - 1].Data + lastBatchData;
226 // store the current batch sum for the next iteration
227 lastBatchData = std::move(currentBatchData);
228 }
229 }
230 });
231
232 return globalSum;
233 }
234
238 vtkIdType GetNumberOfBatches() const { return static_cast<vtkIdType>(this->Batches.size()); }
239
243 unsigned int GetBatchSize() const { return this->BatchSize; }
244
246
249 reference operator[](size_type pos) noexcept { return this->Batches[pos]; }
250 const_reference operator[](size_type pos) const noexcept { return this->Batches[pos]; }
251 iterator begin() noexcept { return this->Batches.begin(); }
252 const_iterator begin() const noexcept { return this->Batches.begin(); }
253 const_iterator cbegin() const noexcept { return this->Batches.cbegin(); }
254 iterator end() noexcept { return this->Batches.end(); }
255 const_iterator end() const noexcept { return this->Batches.end(); }
256 const_iterator cend() const noexcept { return this->Batches.cend(); }
258
259private:
260 vector Batches;
261 unsigned int BatchSize;
262};
263VTK_ABI_NAMESPACE_END
264
265#endif // vtkBatch_h
266// VTK-HeaderTest-Exclude: vtkBatch.h
const_reference operator[](size_type pos) const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:250
vtkIdType GetNumberOfBatches() const
Get the number of batches.
Definition vtkBatch.h:238
const_iterator begin() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:252
unsigned int GetBatchSize() const
Get the batch size.
Definition vtkBatch.h:243
iterator begin() noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:251
void TrimBatches(const std::function< bool(const vtkTBatch &)> shouldRemoveBatch)
Remove batches that should be skipped.
Definition vtkBatch.h:99
iterator end() noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:254
const_iterator end() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:255
TBatchData BuildOffsetsAndGetGlobalSum()
Build offsets in place and returns the Global sum for a vtkBatch with Compact Batch Data.
Definition vtkBatch.h:158
~vtkBatches()=default
const_iterator cbegin() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:253
const_iterator cend() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:256
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:249
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