EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BoundaryCheckBenchmark.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BoundaryCheckBenchmark.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2018 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
12 #include "Acts/Utilities/Units.hpp"
13 
14 #include <algorithm>
15 #include <chrono>
16 #include <functional>
17 #include <iostream>
18 #include <random>
19 #include <vector>
20 
21 using namespace Acts;
22 
23 int main(int /*argc*/, char** /*argv[]*/) {
24  // === PROBLEM DATA ===
25 
26  // Trapezoidal area of interest
27  const Vector2D poly[] = {{0.4, 0.25}, {0.6, 0.25}, {0.8, 0.75}, {0.2, 0.75}};
28 
29  // Covariance matrix which specifies "soft" boundary check tolerance
31  cov << 0.2, 0.02, 0.15, 0.02;
32 
33  // Random tests cover the ((0, 0), (1, 1)) rectangle. 20% of that area is
34  // covered by the trapezoid and most of it is covered by a 3*sigma tolerance
35  // given the above covariance matrix.
36  std::mt19937 rng(42);
37  std::uniform_real_distribution<double> axis(0, 1);
38  auto random_point = [&]() -> Vector2D {
39  return Vector2D(axis(rng), axis(rng));
40  };
41 
42  // This point is inside the area
43  const Vector2D center(0.5, 0.5);
44  // This point is still inside the area, but close to an edge
45  const Vector2D edge_inside(0.401, 0.251);
46  // This point is just a bit outside, should be considered "in" by tolerance
47  const Vector2D edge_outside(0.399, 0.249);
48  // This point should always be considered outside the area
49  const Vector2D far_away(-1000., -1000.);
50 
51  // === BENCHMARKS ===
52 
53  // Number of benchmark runs
54  constexpr int NTESTS = 5'000;
55 
56  // Some checks are much slower, so we tune down benchmark iterations
57  constexpr int NTESTS_SLOW = NTESTS / 10;
58 
59  // Conversely, no-op tests are so fast that we need to tune up iterations
60  constexpr int NTESTS_NOOP = NTESTS * 10;
61 
62  // We use this to switch between iteration counts
63  enum class Mode { NoCheck, FastOutside, SlowOutside };
64 
65  // Benchmark output display
66  auto print_bench_header = [](const std::string& check_name) {
67  std::cout << check_name << ":" << std::endl;
68  };
69  auto print_bench_result = [](const std::string& bench_name,
70  const Acts::Test::MicroBenchmarkResult& res) {
71  std::cout << "- " << bench_name << ": " << res << std::endl;
72  };
73 
74  // Benchmark runner
75  auto run_bench = [&](auto&& iteration, int num_iters,
76  const std::string& bench_name) {
77  auto bench_result = Acts::Test::microBenchmark(iteration, num_iters);
78  print_bench_result(bench_name, bench_result);
79  };
80  auto run_bench_with_inputs = [&](auto&& iterationWithArg, auto&& inputs,
81  const std::string& bench_name) {
82  auto bench_result = Acts::Test::microBenchmark(iterationWithArg, inputs);
83  print_bench_result(bench_name, bench_result);
84  };
85  auto run_all_benches = [&](const BoundaryCheck& check,
86  const std::string& check_name, const Mode mode) {
87  // Announce a set of benchmarks
88  print_bench_header(check_name);
89 
90  // Pre-determined "interesting" test points
91  int num_inside_points;
92  int num_outside_points;
93  switch (mode) {
94  case Mode::NoCheck:
95  num_inside_points = NTESTS_NOOP;
96  num_outside_points = NTESTS_NOOP;
97  break;
98  case Mode::FastOutside:
99  num_inside_points = NTESTS;
100  num_outside_points = NTESTS;
101  break;
102  case Mode::SlowOutside:
103  num_inside_points = NTESTS;
104  num_outside_points = NTESTS_SLOW;
105  };
106  run_bench([&] { return check.isInside(center, poly); }, num_inside_points,
107  "Center");
108  run_bench([&] { return check.isInside(edge_inside, poly); },
109  num_inside_points, "Inside edge");
110  run_bench([&] { return check.isInside(edge_outside, poly); },
111  num_outside_points, "Outside edge");
112  run_bench([&] { return check.isInside(far_away, poly); },
113  num_outside_points, "Far away");
114 
115  // Pre-rolled random points
116  std::vector<Vector2D> points(num_outside_points);
117  std::generate(points.begin(), points.end(), random_point);
118  run_bench_with_inputs(
119  [&](const auto& point) { return check.isInside(point, poly); }, points,
120  "Random");
121  };
122 
123  // Benchmark scenarios
124  run_all_benches(BoundaryCheck(false), "No check", Mode::NoCheck);
125  run_all_benches(BoundaryCheck(true), "No tolerance", Mode::FastOutside);
126  run_all_benches(BoundaryCheck(true, true, 0.6, 0.45), "Abs. tolerance",
127  Mode::SlowOutside);
128  run_all_benches(BoundaryCheck(cov, 3.0), "Cov. tolerance", Mode::SlowOutside);
129 
130  return 0;
131 }