File: Benchmarker.h

package info (click to toggle)
vecgeom 1.2.8%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 24,016 kB
  • sloc: cpp: 88,803; ansic: 6,888; python: 1,035; sh: 582; sql: 538; makefile: 23
file content (361 lines) | stat: -rw-r--r-- 14,889 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/// \file Benchmarker.h
/// \author Johannes de Fine Licht (johannes.definelicht@cern.ch)

#ifndef VECGEOM_BENCHMARKING_BENCHMARKER_H_
#define VECGEOM_BENCHMARKING_BENCHMARKER_H_

#include "VecGeom/base/Config.h"
#include "VecGeom/base/Global.h"

#include "VecGeom/volumes/PlacedVolume.h"
#include "VecGeom/base/SOA3D.h"
#include "BenchmarkResult.h"
#include "VolumePointers.h"

#ifdef VECGEOM_GEANT4
#include "G4VSolid.hh"
#endif

#ifdef VECGEOM_ENABLE_CUDA
#include "VecGeom/backend/cuda/Interface.h"
#endif

#include <list>
#include <vector>
#include <utility> // for std::pair

#if defined(VECGEOM_TEST_VTUNE)
#include "ittnotify.h"
#else
#define __itt_resumme()
#define __itt_start()
#endif

namespace vecgeom {

VECGEOM_HOST_FORWARD_DECLARE(class VPlacedVolume;);
VECGEOM_DEVICE_FORWARD_DECLARE(class VolumePointers;);

/// \brief Benchmarks geometry methods of arbitrary volumes for different
///        backends and compares to any included external libraries.
///
/// In order to run a benchmark, a world volume must be provided to the
/// benchmarker. This volume must have an available bounding box, and can
/// contain any number of daughter volumes. When the benchmark is run, points
/// will be sampled with a bias in regard to these daughter volumes. Deeper
/// hierarchies are not considered. For any level of verbosity above zero, the
/// benchmarker will output results to standard output. However, result structs
/// are available and can be retrieved, containing all information related to a
/// specific run.
/// \sa BenchmarkResult
class Benchmarker {

public:
  typedef typename std::vector<std::pair<Vector3D<Precision>, Vector3D<Precision>>> RayContainer;

private:
  using VPlacedVolume_t = cxx::VPlacedVolume const *;

  VPlacedVolume_t fWorld;
  unsigned fPointCount;
  unsigned fPoolMultiplier;
  unsigned fRepetitions;
  unsigned fMeasurementCount;
  std::list<VolumePointers> fVolumes;
  std::list<BenchmarkResult> fResults;
  int fVerbosity;
  double fToInBias, fInsideBias;
  SOA3D<Precision> *fPointPool;
  SOA3D<Precision> *fDirectionPool;
  SOA3D<Precision> *fInsidePointPoolCache;
  SOA3D<Precision> *fInsideDirectionPoolCache;
  bool fInsideCacheInitialized = false;
  Precision *fStepMax;

  // tolerance for comparisons
  Precision fTolerance;

  // containers to store problematic points
  // this can be filled during evaluation
  std::vector<Vector3D<Precision>> fProblematicContainPoints;

  // a container storing rays : startpoint (Vector3D) plus direction (Vector3D)
  RayContainer fProblematicRays;

// flags indicating whether it is ok to run ROOT/G4
// because in some cases a conversion might not exist
// the Benchmarker class will check this at initialization and
// set these flags accordingly
#ifdef VECGEOM_ROOT
  bool fOkToRunROOT;
#endif
#ifdef VECGEOM_GEANT4
  bool fOkToRunG4;
#endif

#if defined(VECGEOM_TEST_VTUNE)
  __itt_domain *__itt_RunInsideBenchmark = __itt_domain_create("RunInsideBenchmark");
  __itt_domain *__itt_RunToInBenchmark   = __itt_domain_create("RunToInBenchmark");
  __itt_domain *__itt_RunToOutBenchmark  = __itt_domain_create("RunToOutBenchmark");

  __itt_string_handle *__itt_RunInsideSpecialized   = __itt_string_handle_create("RunInsideSpecialized");
  __itt_string_handle *__itt_RunInsideVectorized    = __itt_string_handle_create("RunInsideVectorized");
  __itt_string_handle *__itt_RunInsideUnspecialized = __itt_string_handle_create("RunInsideUnspecialized");

  __itt_string_handle *__itt_RunToInSpecialized   = __itt_string_handle_create("RunToInSpecialized");
  __itt_string_handle *__itt_RunToInVectorized    = __itt_string_handle_create("RunToInVectorized");
  __itt_string_handle *__itt_RunToInUnspecialized = __itt_string_handle_create("RunToInUnspecialized");

  __itt_string_handle *__itt_RunToOutSpecialized   = __itt_string_handle_create("RunToOutSpecialized");
  __itt_string_handle *__itt_RunToOutVectorized    = __itt_string_handle_create("RunToOutVectorized");
  __itt_string_handle *__itt_RunToOutUnspecialized = __itt_string_handle_create("RunToOutUnspecialized");
#endif

public:
  Benchmarker();

  /// \param world Mother volume containing daughters that will be benchmarked.
  ///              The mother volume must have an available bounding box, as it
  ///              is used in the sampling process.
  Benchmarker(VPlacedVolume_t const world);

  ~Benchmarker();

  /// \brief set tolerance for comparisons
  void SetTolerance(Precision tol) { fTolerance = tol; }

  /// \brief get pointer to PointPool (in order to make data available to external users);
  SOA3D<Precision> const *GetPointPool() const { return fPointPool; }

  SOA3D<Precision> const *GetDirectionPool() const { return fDirectionPool; }

  /// \brief Runs all geometry benchmarks.
  /// return 0 if no error found; returns 1 if error found
  int RunBenchmark();

  /// \brief Runs some meta information functions (such as surface arrea, volume and so on) on registered shapes
  /// checks if this information agrees across different implementations (VecGeom, ROOT, Geant4, ...)
  int CompareMetaInformation() const;

  /// \brief Runs a benchmark of the Inside method.
  ///
  /// The fraction of sampled points that will be located inside of daughter
  /// volume is specified by calling SetInsideBias().
  /// \sa SetInsideBias(const double)
  /// return 0 if no error found; returns 1 if error found
  int RunInsideBenchmark();

  /// \brief Runs a benchmark of the DistanceToIn and SafetyToIn methods.
  ///
  /// The fraction of sampled points that should be hitting a daughter volume is
  /// specified by calling SetToInBias().
  /// \sa SetToInBias(const double)
  /// return 0 if no error found; returns 1 if error found
  int RunToInBenchmark();

  /// \brief Runs a benchmark of the DistanceToOut and SafetyToOut methods.
  /// return 0 if no error found; returns 1 if error found
  int RunToOutBenchmark();

  /// \brief Runs a benchmark of the DistanceToOut and SafetyToOut methods.
  /// points start from the surface of the shape
  /// return 0 if no error found; returns 1 if error found
  int RunToOutFromBoundaryBenchmark();

  /// \brief Runs a benchmark of the DistanceToOut and SafetyToOut methods.
  /// points start from the surface of the shape
  /// return 0 if no error found; returns 1 if error found
  int RunToOutFromBoundaryExitingBenchmark();

  /// \brief Runs a benchmark of the DistanceToIn and SafetyToIn methods.
  /// points start from the surface of the shape and directions point inward
  /// return 0 if no error found; returns 1 if error found
  int RunToInFromBoundaryBenchmark();

  /// \brief Runs a benchmark of the DistanceToIn and SafetyToIn methods.
  /// points start from the surface of the shape and directions point inward
  /// return 0 if no error found; returns 1 if error found
  /// tests tracks which have been transported to the boundary and we are asking DistanceToIn again
  int RunToInFromBoundaryExitingBenchmark();

  /// \return Amount of points and directions sampled for each benchmark
  ///         iteration.
  unsigned GetPointCount() const { return fPointCount; }

  /// \return Bias with which directions for DistanceToIn and SafetyToIn are
  ///         sampled.
  double GetToInBias() const { return fToInBias; }

  /// \return Bias with which the points for Inside are sampled.
  double GetInsideBias() const { return fInsideBias; }

  /// \return Multiplier of point and direction pool to use for simulating
  ///         random memory access.
  unsigned GetPoolMultiplier() const { return fPoolMultiplier; }

  /// \return Level of verbosity to standard output.
  int GetVerbosity() const { return fVerbosity; }

  /// \return Amount of iterations the benchmark is run for each time measurement.
  unsigned GetRepetitions() const { return fRepetitions; }

  /// \return Number of time measurements taken by the benchmarker, for same set of input data
  unsigned GetMeasurementCount() const { return fMeasurementCount; }

  /// \return World whose daughters are benchmarked.
  VPlacedVolume_t GetWorld() const { return fWorld; }

  /// \param pointCount Amount of points to benchmark in each iteration.
  void SetPointCount(const unsigned pointCount) { fPointCount = pointCount; }

  /// \param toInBias Fraction of sampled particles that should be facing a
  /// daughter volume.
  void SetToInBias(const double toInBias) { fToInBias = toInBias; }

  /// \param insideBias Fraction of sampled particles that should be contained
  ///                   in a daughter volume.
  void SetInsideBias(const double insideBias) { fInsideBias = insideBias; }

  /// \param Multiplier for the pool of sampled points and directions.
  ///
  /// Can be increased to simulate more random access of memory, but will
  /// disable comparison of output.
  void SetPoolMultiplier(const unsigned poolMultiplier);

  /// \param verbosity Regulates the amount of information printed to standard
  ///                  output.
  ///
  /// If set to zero nothing is printed, but results are stored and can be
  /// retrieved using the GetResults() or PopResults() methods.
  /// \sa GetResults()
  /// \sa PopResults()
  void SetVerbosity(const int verbosity) { fVerbosity = verbosity; }

  /// \param Amount of iterations to run the benchmarks.
  void SetRepetitions(const unsigned repetitions) { fRepetitions = repetitions; }

  /// \param Number of time measurements taken, for same set of input data (random tracks)
  void SetMeasurementCount(const unsigned nmeas) { fMeasurementCount = nmeas; }

  /// \param World volume containing daughters to be benchmarked.
  void SetWorld(VPlacedVolume_t const world);

  /// \return List of results of previously performed benchmarks.
  std::list<BenchmarkResult> const &GetResults() const { return fResults; }

  /// \return List of results of previously performed benchmarks. Clears the internal history.
  std::list<BenchmarkResult> PopResults();

  /// Clear the internal list of results, e.g. to start a new set of results for output
  void ClearResults() { fResults.clear(); }

  std::vector<Vector3D<Precision>> const &GetProblematicContainPoints() const { return fProblematicContainPoints; }

  RayContainer const &GetProblematicRays() const { return fProblematicRays; }

private:
  void GenerateVolumePointers(VPlacedVolume_t const vol);

  BenchmarkResult GenerateBenchmarkResult(Precision elapsed, const EBenchmarkedMethod method,
                                          const EBenchmarkedLibrary library, const Precision bias) const;
  void RunInsideSpecialized(bool *contains, Inside_t *inside);
  void RunToInSpecialized(Precision *distances, Precision *safeties);
  void RunToOutSpecialized(Precision *distances, Precision *safeties);

  void RunInsideVectorized(bool *contains, Inside_t *inside);
  void RunToInVectorized(Precision *distances, Precision *safeties);
  void RunToOutVectorized(Precision *distances, Precision *safeties);

  void RunInsideUnspecialized(bool *contains, Inside_t *inside);
  void RunToInUnspecialized(Precision *distances, Precision *safeties);
  void RunToOutUnspecialized(Precision *distances, Precision *safeties);

#ifdef VECGEOM_ROOT
  void RunInsideRoot(bool *inside);
  void RunToInRoot(Precision *distances, Precision *safeties);
  void RunToOutRoot(Precision *distances, Precision *safeties);
#endif
#ifdef VECGEOM_GEANT4
  void RunInsideGeant4(::EInside *inside);
  void RunToInGeant4(Precision *distances, Precision *safeties);
  void RunToOutGeant4(Precision *distances, Precision *safeties);
#endif
#ifdef VECGEOM_ENABLE_CUDA
  void RunInsideCuda(Precision *posX, Precision *posY, Precision *posZ, bool *contains, Inside_t *inside);
  void RunToInCuda(Precision *posX, Precision *posY, Precision *posZ, Precision *dirX, Precision *dirY, Precision *dirZ,
                   Precision *distances, Precision *safeties);
  void RunToOutCuda(Precision *posX, Precision *posY, Precision *posZ, Precision *dirX, Precision *dirY,
                    Precision *dirZ, Precision *distances, Precision *safeties);
  void GetVolumePointers(std::list<cxx::DevicePtr<cuda::VPlacedVolume>> &volumesGpu);
#endif

  template <typename Type>
  Type *AllocateAligned() const;

  template <typename Type>
  static void FreeAligned(Type *const distance);

  // internal method to crosscheck results; fills a container with problematic cases
  int CompareDistances(SOA3D<Precision> *points, SOA3D<Precision> *directions, Precision const *const specialized,
                       Precision const *const vectorized, Precision const *const unspecialized,
#ifdef VECGEOM_ROOT
                       Precision const *const root,
#endif
#ifdef VECGEOM_GEANT4
                       Precision const *const geant4,
#endif
#ifdef VECGEOM_ENABLE_CUDA
                       Precision const *const cuda,
#endif
                       char const *const method);

  // internal method to crosscheck results from boundary; fills a container with problematic cases
  int CheckDistancesFromBoundary(Precision expected, SOA3D<Precision> *points, SOA3D<Precision> *directions,
                                 Precision const *const specialized, Precision const *const vectorized,
                                 Precision const *const unspecialized,
#ifdef VECGEOM_ROOT
                                 Precision const *const root,
#endif
#ifdef VECGEOM_GEANT4
                                 Precision const *const geant4,
#endif
#ifdef VECGEOM_ENABLE_CUDA
                                 Precision const *const cuda,
#endif
                                 char const *const method);

  int CompareSafeties(SOA3D<Precision> *points, SOA3D<Precision> *directions, Precision const *const specialized,
                      Precision const *const vectorized, Precision const *const unspecialized,
#ifdef VECGEOM_ROOT
                      Precision const *const root,
#endif
#ifdef VECGEOM_GEANT4
                      Precision const *const geant4,
#endif
#ifdef VECGEOM_ENABLE_CUDA
                      Precision const *const cuda,
#endif
                      char const *const method) const;

  // special version for boundary points
  // here we know that result has to be zero
  int CheckSafetiesOnBoundary(SOA3D<Precision> *points, SOA3D<Precision> *directions,
                              Precision const *const specialized, Precision const *const vectorized,
                              Precision const *const unspecialized,
#ifdef VECGEOM_ROOT
                              Precision const *const root,
#endif
#ifdef VECGEOM_GEANT4
                              Precision const *const geant4,
#endif
#ifdef VECGEOM_ENABLE_CUDA
                              Precision const *const cuda,
#endif
                              char const *const method) const;

  void InitInsideCaches();
};

} // End namespace vecgeom

#endif // VECGEOM_BENCHMARKING_BENCHMARKER_H_