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