VTK  9.6.20260522
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
25
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{
44 TBatchData Data;
45};
46
47//-----------------------------------------------------------------------------
48template <typename TBatchData>
50{
51private:
52 using vtkTBatch = vtkBatch<TBatchData>;
53 using vector = std::vector<vtkTBatch>;
54 using size_type = typename vector::size_type;
55 using reference = typename vector::reference;
56 using const_reference = typename vector::const_reference;
57 using iterator = typename vector::iterator;
58 using const_iterator = typename vector::const_iterator;
59
60public:
62 : BatchSize(0)
63 {
64 }
65 ~vtkBatches() = default;
66
70 void Initialize(vtkIdType numberOfElements, unsigned int batchSize = 1000)
71 {
72 this->BatchSize = batchSize;
73
74 const auto batchSizeSigned = static_cast<vtkIdType>(batchSize);
75 const auto numberOfBatches = ((numberOfElements - 1) / batchSizeSigned) + 1;
76 this->Batches.resize(static_cast<size_t>(numberOfBatches));
77 const auto lastBatchId = numberOfBatches - 1;
78
79 vtkSMPTools::For(0, numberOfBatches,
80 [&](vtkIdType beginBatchId, vtkIdType endBatchId)
81 {
82 vtkIdType endIdValues[2] = { -1, numberOfElements };
83 for (vtkIdType batchId = beginBatchId; batchId < endBatchId; ++batchId)
84 {
85 auto& batch = this->Batches[batchId];
86 batch.BeginId = batchId * batchSizeSigned;
87 endIdValues[0] = (batchId + 1) * batchSizeSigned;
88 batch.EndId = endIdValues[batchId == lastBatchId];
89 }
90 });
91 }
92
96 void TrimBatches(const std::function<bool(const vtkTBatch&)> shouldRemoveBatch)
97 {
98 const vtkIdType numberOfBatches = this->GetNumberOfBatches();
99 if (numberOfBatches == 0)
100 {
101 return;
102 }
103 const vtkIdType numberOfThreads =
104 std::min(static_cast<vtkIdType>(vtkSMPTools::GetEstimatedNumberOfThreads()), numberOfBatches);
105 const vtkIdType lastThreadId = numberOfThreads - 1;
106 const vtkIdType numberOfBatchesPerThread = numberOfBatches / numberOfThreads;
107
108 std::vector<vtkIdType> tlInterEndBatchId;
109 tlInterEndBatchId.resize(static_cast<size_t>(numberOfThreads));
110
111 // perform batch trimming of batch segments
112 vtkSMPTools::For(0, numberOfThreads,
113 [&](vtkIdType beginThreadId, vtkIdType endThreadId)
114 {
115 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
116 {
117 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
118 const vtkIdType endBatchId =
119 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
120 auto beginBatchIter = this->Batches.begin() + beginBatchId;
121 auto endBatchIter = this->Batches.begin() + endBatchId;
122 auto newEndBatchIter = std::remove_if(beginBatchIter, endBatchIter, shouldRemoveBatch);
123 tlInterEndBatchId[threadId] =
124 beginBatchId + std::distance(beginBatchIter, newEndBatchIter);
125 }
126 });
127 // compute the new end batch ids;
128 std::vector<vtkIdType> tlNewEndBatchId;
129 tlNewEndBatchId.resize(static_cast<size_t>(numberOfThreads));
130 tlNewEndBatchId[0] = tlInterEndBatchId[0];
131 for (vtkIdType threadId = 1; threadId < numberOfThreads; ++threadId)
132 {
133 const vtkIdType beginOldBatchId = threadId * numberOfBatchesPerThread;
134 const auto& prevNewEndBatchId = tlNewEndBatchId[threadId - 1];
135 const vtkIdType distance = tlInterEndBatchId[threadId] - beginOldBatchId;
136 tlNewEndBatchId[threadId] = prevNewEndBatchId + distance;
137 // Only move if the destination is different from the source
138 if (prevNewEndBatchId != beginOldBatchId)
139 {
140 std::move(this->Batches.begin() + beginOldBatchId,
141 this->Batches.begin() + tlInterEndBatchId[threadId],
142 this->Batches.begin() + prevNewEndBatchId);
143 }
144 }
145 this->Batches.erase(this->Batches.begin() + tlNewEndBatchId[lastThreadId], this->Batches.end());
146 }
147
160 {
161 const vtkIdType numberOfBatches = this->GetNumberOfBatches();
162 if (numberOfBatches == 0)
163 {
164 return TBatchData{};
165 }
166 const vtkIdType numberOfThreads =
167 std::min(static_cast<vtkIdType>(vtkSMPTools::GetEstimatedNumberOfThreads()), numberOfBatches);
168 const vtkIdType lastThreadId = numberOfThreads - 1;
169 const vtkIdType numberOfBatchesPerThread = numberOfBatches / numberOfThreads;
170
171 // calculate the thread local sums;
172 std::vector<TBatchData> tlSums;
173 tlSums.resize(static_cast<size_t>(numberOfThreads));
174
175 vtkSMPTools::For(0, numberOfThreads,
176 [&](vtkIdType beginThreadId, vtkIdType endThreadId)
177 {
178 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
179 {
180 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
181 const vtkIdType endBatchId =
182 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
183
184 auto& threadSum = tlSums[threadId];
185 for (vtkIdType batchId = beginBatchId; batchId < endBatchId; ++batchId)
186 {
187 threadSum += this->Batches[batchId].Data;
188 }
189 }
190 });
191
192 // calculate the global sum;
193 TBatchData globalSum;
194 for (const auto& threadSum : tlSums)
195 {
196 globalSum += threadSum;
197 }
198
199 // calculate the thread local offsets using the thread local sums
200 std::vector<TBatchData> tlOffsets;
201 tlOffsets.resize(static_cast<size_t>(numberOfThreads));
202 for (vtkIdType threadId = 1; threadId < numberOfThreads; ++threadId)
203 {
204 tlOffsets[threadId] = tlOffsets[threadId - 1] + tlSums[threadId - 1];
205 }
206
207 // convert the batch sums to offsets using the thread local offsets
208 vtkSMPTools::For(0, numberOfThreads,
209 [&](vtkIdType beginThreadId, vtkIdType endThreadId)
210 {
211 for (vtkIdType threadId = beginThreadId; threadId < endThreadId; ++threadId)
212 {
213 const vtkIdType beginBatchId = threadId * numberOfBatchesPerThread;
214 const vtkIdType endBatchId =
215 threadId != lastThreadId ? (threadId + 1) * numberOfBatchesPerThread : numberOfBatches;
216
217 // store the first batch sum
218 auto lastBatchData = this->Batches[beginBatchId].Data;
219 // convert the first batch sum to an offset
220 this->Batches[beginBatchId].Data = tlOffsets[threadId];
221 for (vtkIdType batchId = beginBatchId + 1; batchId < endBatchId; ++batchId)
222 {
223 // store the current batch sum
224 const auto currentBatchData = this->Batches[batchId].Data;
225 // // Compute the offsets for the current batch
226 const auto newData = this->Batches[batchId - 1].Data + lastBatchData;
227 // // Convert the current batch sum to the computed offsets
228 this->Batches[batchId].Data = newData;
229 // store the current batch sum for the next iteration
230 lastBatchData = std::move(currentBatchData);
231 }
232 }
233 });
234
235 return globalSum;
236 }
237
241 vtkIdType GetNumberOfBatches() const { return static_cast<vtkIdType>(this->Batches.size()); }
242
246 unsigned int GetBatchSize() const { return this->BatchSize; }
247
249
252 reference operator[](size_type pos) noexcept { return this->Batches[pos]; }
253 const_reference operator[](size_type pos) const noexcept { return this->Batches[pos]; }
254 iterator begin() noexcept { return this->Batches.begin(); }
255 const_iterator begin() const noexcept { return this->Batches.begin(); }
256 const_iterator cbegin() const noexcept { return this->Batches.cbegin(); }
257 iterator end() noexcept { return this->Batches.end(); }
258 const_iterator end() const noexcept { return this->Batches.end(); }
259 const_iterator cend() const noexcept { return this->Batches.cend(); }
261
262private:
263 vector Batches;
264 unsigned int BatchSize;
265};
266VTK_ABI_NAMESPACE_END
267
268#endif // vtkBatch_h
269// VTK-HeaderTest-Exclude: vtkBatch.h
const_reference operator[](size_type pos) const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:253
vtkIdType GetNumberOfBatches() const
Get the number of batches.
Definition vtkBatch.h:241
const_iterator begin() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:255
unsigned int GetBatchSize() const
Get the batch size.
Definition vtkBatch.h:246
iterator begin() noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:254
void TrimBatches(const std::function< bool(const vtkTBatch &)> shouldRemoveBatch)
Remove batches that should be skipped.
Definition vtkBatch.h:96
iterator end() noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:257
const_iterator end() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:258
TBatchData BuildOffsetsAndGetGlobalSum()
Build offsets in place and returns the Global sum for a vtkBatch with Compact Batch Data.
Definition vtkBatch.h:159
~vtkBatches()=default
const_iterator cbegin() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:256
const_iterator cend() const noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:259
void Initialize(vtkIdType numberOfElements, unsigned int batchSize=1000)
Initialize the batches.
Definition vtkBatch.h:70
reference operator[](size_type pos) noexcept
The following methods expose the underlying vector.
Definition vtkBatch.h:252
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
TBatchData Data
Definition vtkBatch.h:44
vtkIdType EndId
Definition vtkBatch.h:43
vtkIdType BeginId
Definition vtkBatch.h:42
int vtkIdType
Definition vtkType.h:363