1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10
11 #include "Benchmarker.h"
12
13 #include <vtkm/Math.h>
14 #include <vtkm/VectorAnalysis.h>
15
16 #include <vtkm/cont/ArrayHandle.h>
17 #include <vtkm/cont/CellSetStructured.h>
18 #include <vtkm/cont/Invoker.h>
19 #include <vtkm/cont/Timer.h>
20 #include <vtkm/cont/UncertainArrayHandle.h>
21
22 #include <vtkm/worklet/WorkletMapField.h>
23 #include <vtkm/worklet/WorkletMapTopology.h>
24
25 #include <vtkm/cont/testing/Testing.h>
26
27 #include <cctype>
28 #include <random>
29 #include <string>
30
31 namespace
32 {
33
34 #define CUBE_SIZE 256
35
36 using ValueTypes = vtkm::List<vtkm::UInt32, vtkm::Int32, vtkm::Int64, vtkm::Float32, vtkm::Float64>;
37
38 using ValueUncertainHandle =
39 vtkm::cont::UncertainArrayHandle<ValueTypes, vtkm::cont::StorageListBasic>;
40
41 // Hold configuration state (e.g. active device)
42 vtkm::cont::InitializeResult Config;
43
44 class AveragePointToCell : public vtkm::worklet::WorkletVisitCellsWithPoints
45 {
46 public:
47 using ControlSignature = void(FieldInPoint inPoints, CellSetIn cellset, FieldOutCell outCells);
48 using ExecutionSignature = void(_1, PointCount, _3);
49 using InputDomain = _2;
50
51 template <typename PointValueVecType, typename OutType>
operator ()(const PointValueVecType & pointValues,const vtkm::IdComponent & numPoints,OutType & average) const52 VTKM_EXEC void operator()(const PointValueVecType& pointValues,
53 const vtkm::IdComponent& numPoints,
54 OutType& average) const
55 {
56 OutType sum = static_cast<OutType>(pointValues[0]);
57 for (vtkm::IdComponent pointIndex = 1; pointIndex < numPoints; ++pointIndex)
58 {
59 sum = sum + static_cast<OutType>(pointValues[pointIndex]);
60 }
61
62 average = sum / static_cast<OutType>(numPoints);
63 }
64 };
65
66 class AverageCellToPoint : public vtkm::worklet::WorkletVisitPointsWithCells
67 {
68 public:
69 using ControlSignature = void(FieldInCell inCells, CellSetIn topology, FieldOut outPoints);
70 using ExecutionSignature = void(_1, _3, CellCount);
71 using InputDomain = _2;
72
73 template <typename CellVecType, typename OutType>
operator ()(const CellVecType & cellValues,OutType & avgVal,const vtkm::IdComponent & numCellIDs) const74 VTKM_EXEC void operator()(const CellVecType& cellValues,
75 OutType& avgVal,
76 const vtkm::IdComponent& numCellIDs) const
77 {
78 //simple functor that returns the average cell Value.
79 avgVal = vtkm::TypeTraits<OutType>::ZeroInitialization();
80 if (numCellIDs != 0)
81 {
82 for (vtkm::IdComponent cellIndex = 0; cellIndex < numCellIDs; ++cellIndex)
83 {
84 avgVal += static_cast<OutType>(cellValues[cellIndex]);
85 }
86 avgVal = avgVal / static_cast<OutType>(numCellIDs);
87 }
88 }
89 };
90
91 // -----------------------------------------------------------------------------
92 template <typename T>
93 class Classification : public vtkm::worklet::WorkletVisitCellsWithPoints
94 {
95 public:
96 using ControlSignature = void(FieldInPoint inNodes, CellSetIn cellset, FieldOutCell outCaseId);
97 using ExecutionSignature = void(_1, _3);
98 using InputDomain = _2;
99
100 T IsoValue;
101
102 VTKM_CONT
Classification(T isovalue)103 Classification(T isovalue)
104 : IsoValue(isovalue)
105 {
106 }
107
108 template <typename FieldInType>
operator ()(const FieldInType & fieldIn,vtkm::IdComponent & caseNumber) const109 VTKM_EXEC void operator()(const FieldInType& fieldIn, vtkm::IdComponent& caseNumber) const
110 {
111 using FieldType = typename vtkm::VecTraits<FieldInType>::ComponentType;
112 const FieldType iso = static_cast<FieldType>(this->IsoValue);
113
114 caseNumber = ((fieldIn[0] > iso) | (fieldIn[1] > iso) << 1 | (fieldIn[2] > iso) << 2 |
115 (fieldIn[3] > iso) << 3 | (fieldIn[4] > iso) << 4 | (fieldIn[5] > iso) << 5 |
116 (fieldIn[6] > iso) << 6 | (fieldIn[7] > iso) << 7);
117 }
118 };
119
120 template <typename T, typename Enable = void>
121 struct NumberGenerator
122 {
123 };
124
125 template <typename T>
126 struct NumberGenerator<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
127 {
128 std::mt19937 rng;
129 std::uniform_real_distribution<T> distribution;
NumberGenerator__anonc66b6a110111::NumberGenerator130 NumberGenerator(T low, T high)
131 : rng()
132 , distribution(low, high)
133 {
134 }
next__anonc66b6a110111::NumberGenerator135 T next() { return distribution(rng); }
136 };
137
138 template <typename T>
139 struct NumberGenerator<T, typename std::enable_if<!std::is_floating_point<T>::value>::type>
140 {
141 std::mt19937 rng;
142 std::uniform_int_distribution<T> distribution;
143
NumberGenerator__anonc66b6a110111::NumberGenerator144 NumberGenerator(T low, T high)
145 : rng()
146 , distribution(low, high)
147 {
148 }
next__anonc66b6a110111::NumberGenerator149 T next() { return distribution(rng); }
150 };
151
152 // Returns an extra random value.
153 // Like, an additional random value.
154 // Not a random value that's somehow "extra random".
155 template <typename ArrayT>
FillRandomValues(ArrayT & array,vtkm::Id size,vtkm::Float64 min,vtkm::Float64 max)156 VTKM_CONT typename ArrayT::ValueType FillRandomValues(ArrayT& array,
157 vtkm::Id size,
158 vtkm::Float64 min,
159 vtkm::Float64 max)
160 {
161 using ValueType = typename ArrayT::ValueType;
162
163 NumberGenerator<ValueType> generator{ static_cast<ValueType>(min), static_cast<ValueType>(max) };
164 array.Allocate(size);
165 auto portal = array.WritePortal();
166 for (vtkm::Id i = 0; i < size; ++i)
167 {
168 portal.Set(i, generator.next());
169 }
170 return generator.next();
171 }
172
173 template <typename Value>
174 struct BenchCellToPointAvgImpl
175 {
176 vtkm::cont::ArrayHandle<Value> Input;
177
178 ::benchmark::State& State;
179 vtkm::Id CubeSize;
180 vtkm::Id NumCells;
181
182 vtkm::cont::Timer Timer;
183 vtkm::cont::Invoker Invoker;
184
185 VTKM_CONT
BenchCellToPointAvgImpl__anonc66b6a110111::BenchCellToPointAvgImpl186 BenchCellToPointAvgImpl(::benchmark::State& state)
187 : State{ state }
188 , CubeSize{ CUBE_SIZE }
189 , NumCells{ (this->CubeSize - 1) * (this->CubeSize - 1) * (this->CubeSize - 1) }
190 , Timer{ Config.Device }
191 , Invoker{ Config.Device }
192 {
193 FillRandomValues(this->Input, this->NumCells, 1., 100.);
194
195 { // Configure label:
196 std::ostringstream desc;
197 desc << "CubeSize:" << this->CubeSize;
198 this->State.SetLabel(desc.str());
199 }
200 }
201
202 template <typename BenchArrayType>
Run__anonc66b6a110111::BenchCellToPointAvgImpl203 VTKM_CONT void Run(const BenchArrayType& input)
204 {
205 vtkm::cont::CellSetStructured<3> cellSet;
206 cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
207 vtkm::cont::ArrayHandle<Value> result;
208
209 for (auto _ : this->State)
210 {
211 (void)_;
212 this->Timer.Start();
213 this->Invoker(AverageCellToPoint{}, input, cellSet, result);
214 this->Timer.Stop();
215
216 this->State.SetIterationTime(this->Timer.GetElapsedTime());
217 }
218
219 // #items = #points
220 const int64_t iterations = static_cast<int64_t>(this->State.iterations());
221 this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfPoints()) * iterations);
222 }
223 };
224
225 template <typename ValueType>
BenchCellToPointAvgStatic(::benchmark::State & state)226 void BenchCellToPointAvgStatic(::benchmark::State& state)
227 {
228 BenchCellToPointAvgImpl<ValueType> impl{ state };
229 impl.Run(impl.Input);
230 };
231 VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgStatic, ValueTypes);
232
233 template <typename ValueType>
BenchCellToPointAvgDynamic(::benchmark::State & state)234 void BenchCellToPointAvgDynamic(::benchmark::State& state)
235 {
236 BenchCellToPointAvgImpl<ValueType> impl{ state };
237 impl.Run(ValueUncertainHandle{ impl.Input });
238 };
239 VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgDynamic, ValueTypes);
240
241 template <typename Value>
242 struct BenchPointToCellAvgImpl
243 {
244 vtkm::cont::ArrayHandle<Value> Input;
245
246 ::benchmark::State& State;
247 vtkm::Id CubeSize;
248 vtkm::Id NumPoints;
249
250 vtkm::cont::Timer Timer;
251 vtkm::cont::Invoker Invoker;
252
253 VTKM_CONT
BenchPointToCellAvgImpl__anonc66b6a110111::BenchPointToCellAvgImpl254 BenchPointToCellAvgImpl(::benchmark::State& state)
255 : State{ state }
256 , CubeSize{ CUBE_SIZE }
257 , NumPoints{ (this->CubeSize) * (this->CubeSize) * (this->CubeSize) }
258 , Timer{ Config.Device }
259 , Invoker{ Config.Device }
260 {
261 FillRandomValues(this->Input, this->NumPoints, 1., 100.);
262
263 { // Configure label:
264 std::ostringstream desc;
265 desc << "CubeSize:" << this->CubeSize;
266 this->State.SetLabel(desc.str());
267 }
268 }
269
270 template <typename BenchArrayType>
Run__anonc66b6a110111::BenchPointToCellAvgImpl271 VTKM_CONT void Run(const BenchArrayType& input)
272 {
273 vtkm::cont::CellSetStructured<3> cellSet;
274 cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
275 vtkm::cont::ArrayHandle<Value> result;
276
277 for (auto _ : this->State)
278 {
279 (void)_;
280 this->Timer.Start();
281 this->Invoker(AveragePointToCell{}, input, cellSet, result);
282 this->Timer.Stop();
283
284 this->State.SetIterationTime(this->Timer.GetElapsedTime());
285 }
286
287 // #items = #cells
288 const int64_t iterations = static_cast<int64_t>(this->State.iterations());
289 this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfCells()) * iterations);
290 }
291 };
292
293 template <typename ValueType>
BenchPointToCellAvgStatic(::benchmark::State & state)294 void BenchPointToCellAvgStatic(::benchmark::State& state)
295 {
296 BenchPointToCellAvgImpl<ValueType> impl{ state };
297 impl.Run(impl.Input);
298 };
299 VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgStatic, ValueTypes);
300
301 template <typename ValueType>
BenchPointToCellAvgDynamic(::benchmark::State & state)302 void BenchPointToCellAvgDynamic(::benchmark::State& state)
303 {
304 BenchPointToCellAvgImpl<ValueType> impl{ state };
305 impl.Run(ValueUncertainHandle{ impl.Input });
306 };
307 VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgDynamic, ValueTypes);
308
309 template <typename Value>
310 struct BenchClassificationImpl
311 {
312 vtkm::cont::ArrayHandle<Value> Input;
313
314 ::benchmark::State& State;
315 vtkm::Id CubeSize;
316 vtkm::Id DomainSize;
317 Value IsoValue;
318
319 vtkm::cont::Timer Timer;
320 vtkm::cont::Invoker Invoker;
321
322 VTKM_CONT
BenchClassificationImpl__anonc66b6a110111::BenchClassificationImpl323 BenchClassificationImpl(::benchmark::State& state)
324 : State{ state }
325 , CubeSize{ CUBE_SIZE }
326 , DomainSize{ this->CubeSize * this->CubeSize * this->CubeSize }
327 , Timer{ Config.Device }
328 , Invoker{ Config.Device }
329 {
330 this->IsoValue = FillRandomValues(this->Input, this->DomainSize, 1., 100.);
331
332 { // Configure label:
333 std::ostringstream desc;
334 desc << "CubeSize:" << this->CubeSize;
335 this->State.SetLabel(desc.str());
336 }
337 }
338
339 template <typename BenchArrayType>
Run__anonc66b6a110111::BenchClassificationImpl340 VTKM_CONT void Run(const BenchArrayType& input)
341 {
342 vtkm::cont::CellSetStructured<3> cellSet;
343 cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
344 vtkm::cont::ArrayHandle<vtkm::IdComponent> result;
345
346 Classification<Value> worklet(this->IsoValue);
347
348 for (auto _ : this->State)
349 {
350 (void)_;
351 this->Timer.Start();
352 this->Invoker(worklet, input, cellSet, result);
353 this->Timer.Stop();
354
355 this->State.SetIterationTime(this->Timer.GetElapsedTime());
356 }
357
358 // #items = #cells
359 const int64_t iterations = static_cast<int64_t>(this->State.iterations());
360 this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfCells()) * iterations);
361 }
362 };
363
364 template <typename ValueType>
BenchClassificationStatic(::benchmark::State & state)365 void BenchClassificationStatic(::benchmark::State& state)
366 {
367 BenchClassificationImpl<ValueType> impl{ state };
368 impl.Run(impl.Input);
369 };
370 VTKM_BENCHMARK_TEMPLATES(BenchClassificationStatic, ValueTypes);
371
372 template <typename ValueType>
BenchClassificationDynamic(::benchmark::State & state)373 void BenchClassificationDynamic(::benchmark::State& state)
374 {
375 BenchClassificationImpl<ValueType> impl{ state };
376 impl.Run(ValueUncertainHandle{ impl.Input });
377 };
378 VTKM_BENCHMARK_TEMPLATES(BenchClassificationDynamic, ValueTypes);
379
380 } // end anon namespace
381
main(int argc,char * argv[])382 int main(int argc, char* argv[])
383 {
384 // Parse VTK-m options:
385 auto opts = vtkm::cont::InitializeOptions::RequireDevice;
386
387 std::vector<char*> args(argv, argv + argc);
388 vtkm::bench::detail::InitializeArgs(&argc, args, opts);
389
390 // Parse VTK-m options:
391 Config = vtkm::cont::Initialize(argc, args.data(), opts);
392
393 // This occurs when it is help
394 if (opts == vtkm::cont::InitializeOptions::None)
395 {
396 std::cout << Config.Usage << std::endl;
397 }
398 else
399 {
400 vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
401 }
402
403 // handle benchmarking related args and run benchmarks:
404 VTKM_EXECUTE_BENCHMARKS(argc, args.data());
405 }
406