VTK  9.7.1
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 
37 VTK_ABI_NAMESPACE_BEGIN
38 //-----------------------------------------------------------------------------
39 template <typename TBatchData>
40 struct vtkBatch
41 {
44  TBatchData Data;
45 };
46 
47 //-----------------------------------------------------------------------------
48 template <typename TBatchData>
50 {
51 private:
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 
60 public:
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 
262 private:
263  vector Batches;
264  unsigned int BatchSize;
265 };
266 VTK_ABI_NAMESPACE_END
267 
268 #endif // vtkBatch_h
269 // VTK-HeaderTest-Exclude: vtkBatch.h
const_iterator end() const noexcept
The following methods expose the underlying vector.
Definition: vtkBatch.h:258
~vtkBatches()=default
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
static int GetEstimatedNumberOfThreads()
Get the estimated number of threads being used by the backend.
iterator begin() noexcept
The following methods expose the underlying vector.
Definition: vtkBatch.h:254
int vtkIdType
Definition: vtkType.h:363
const_reference operator[](size_type pos) const noexcept
The following methods expose the underlying vector.
Definition: vtkBatch.h:253
vtkBatches()
Definition: vtkBatch.h:61
static const unsigned int numberOfElements
vtkIdType BeginId
Definition: vtkBatch.h:42
TBatchData Data
Definition: vtkBatch.h:44
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
TBatchData BuildOffsetsAndGetGlobalSum()
Build offsets in place and returns the Global sum for a vtkBatch with Compact Batch Data...
Definition: vtkBatch.h:159
reference operator[](size_type pos) noexcept
The following methods expose the underlying vector.
Definition: vtkBatch.h:252
static void For(vtkIdType first, vtkIdType last, vtkIdType grain, Functor &f)
Execute a for operation in parallel.
Definition: vtkSMPTools.h:238
void Initialize(vtkIdType numberOfElements, unsigned int batchSize=1000)
Initialize the batches.
Definition: vtkBatch.h:70
vtkBatch is a simple structure that holds a begin and end id.
Definition: vtkBatch.h:40
unsigned int GetBatchSize() const
Get the batch size.
Definition: vtkBatch.h:246
vtkIdType EndId
Definition: vtkBatch.h:43
const_iterator cend() const noexcept
The following methods expose the underlying vector.
Definition: vtkBatch.h:259
const_iterator cbegin() const noexcept
The following methods expose the underlying vector.
Definition: vtkBatch.h:256