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_
|