File indexing completed on 2026-05-27 07:24:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "algebra/vc_aos.hpp"
0013 #include "algebra/vc_soa.hpp"
0014
0015
0016 #include "detray/definitions/containers.hpp"
0017 #include "detray/definitions/indexing.hpp"
0018 #include "detray/geometry/mask.hpp"
0019 #include "detray/geometry/shapes.hpp"
0020 #include "detray/geometry/surface_descriptor.hpp"
0021 #include "detray/navigation/intersection/ray_intersector.hpp"
0022 #include "detray/tracks/ray.hpp"
0023 #include "detray/utils/logging.hpp"
0024
0025
0026 #include "detray/benchmarks/types.hpp"
0027
0028
0029 #include "detray/test/common/track_generators.hpp"
0030 #include "detray/test/utils/planes_along_direction.hpp"
0031
0032
0033 #include <benchmark/benchmark.h>
0034
0035
0036 #include <algorithm>
0037
0038 using namespace detray;
0039
0040 static constexpr unsigned int theta_steps{2000u};
0041 static constexpr unsigned int phi_steps{2000u};
0042 static constexpr unsigned int n_surfaces{16u};
0043
0044
0045 using algebra_v = detray::vc_soa<benchmarks::scalar>;
0046
0047
0048
0049 using algebra_vc_aos = detray::vc_aos<benchmarks::scalar>;
0050
0051
0052 using algebra_s = algebra_vc_aos;
0053
0054
0055 constexpr std::size_t simd_size{dscalar<algebra_v>::size()};
0056
0057 using ray_t = detail::ray<algebra_s>;
0058
0059 namespace {
0060
0061 enum class mask_id : unsigned int {
0062 e_rectangle2D = 0,
0063 e_cylinder2D = 1,
0064 e_conc_cylinder3 = 2,
0065 };
0066
0067 enum class material_id : unsigned int {
0068 e_material_slab = 0,
0069 };
0070
0071
0072 using mask_link_t = dtyped_index<mask_id, dindex>;
0073 using material_link_t = dtyped_index<material_id, dindex>;
0074
0075 using surface_desc_t = surface_descriptor<mask_link_t, material_link_t>;
0076
0077
0078 std::vector<ray_t> generate_rays() {
0079 using ray_generator_t = uniform_track_generator<ray_t>;
0080
0081
0082 auto ray_generator = ray_generator_t{};
0083 ray_generator.config().theta_steps(theta_steps).phi_steps(phi_steps);
0084
0085 std::vector<ray_t> rays;
0086 std::ranges::copy(ray_generator, std::back_inserter(rays));
0087
0088 return rays;
0089 }
0090
0091
0092 template <concepts::algebra algebra_t>
0093 dvector<dscalar<algebra_t>> get_dists(std::size_t n) {
0094 using scalar_t = dscalar<algebra_t>;
0095
0096 dvector<benchmarks::scalar> dists;
0097
0098 for (std::size_t i = 1u; i <= n; ++i) {
0099 dists.push_back(static_cast<scalar_t>(i));
0100 }
0101
0102 return dists;
0103 }
0104
0105
0106 template <>
0107 dvector<dscalar<algebra_v>> get_dists<algebra_v>(std::size_t n) {
0108 using scalar_t = dscalar<algebra_v>;
0109 using value_t = typename algebra_v::value_type;
0110
0111 dvector<scalar_t> dists;
0112 dists.resize(static_cast<std::size_t>(std::ceil(n / simd_size)));
0113 for (std::size_t i = 0u; i < dists.size(); ++i) {
0114 dists[i] = scalar_t::IndexesFromZero() +
0115 scalar_t(static_cast<value_t>(i)) * simd_size + scalar_t(1.f);
0116 }
0117
0118 return dists;
0119 }
0120
0121 }
0122
0123
0124 void BM_INTERSECT_PLANES_AOS(benchmark::State& state) {
0125 using mask_t = mask<rectangle2D, algebra_s, std::uint_least16_t>;
0126
0127 auto dists = get_dists<algebra_s>(n_surfaces);
0128 auto [plane_descs, transforms] = test::planes_along_direction<algebra_s>(
0129 dists, dvector3D<algebra_s>{1.f, 1.f, 1.f});
0130
0131 constexpr mask_t rect{0u, 100.f, 200.f};
0132 std::vector<mask_t> masks(plane_descs.size(), rect);
0133
0134 const auto rays = generate_rays();
0135 const auto pi = ray_intersector<rectangle2D, algebra_s>{};
0136
0137 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0138 std::size_t hit{0u};
0139 std::size_t miss{0u};
0140 #endif
0141
0142 for (auto _ : state) {
0143 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0144 hit = 0u;
0145 miss = 0u;
0146 #endif
0147
0148
0149 for (const auto& ray : rays) {
0150 for (std::size_t i = 0u; i < plane_descs.size(); ++i) {
0151 auto is = pi(ray, plane_descs[i], masks[i], transforms[i]);
0152
0153 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0154 if (is.is_inside()) {
0155 ++hit;
0156 } else {
0157 ++miss;
0158 }
0159 #endif
0160
0161 benchmark::DoNotOptimize(is);
0162 }
0163 }
0164 }
0165 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0166 DETRAY_INFO_HOST(mask_t::shape::name
0167 << " AoS: hit/miss ... " << hit << " / " << miss
0168 << " (total: " << rays.size() * masks.size() << ")");
0169 #endif
0170 }
0171
0172 BENCHMARK(BM_INTERSECT_PLANES_AOS)
0173 #ifdef DETRAY_BENCHMARK_MULTITHREAD
0174 ->ThreadRange(1, benchmark::CPUInfo::Get().num_cpus)
0175 #endif
0176 ->Unit(benchmark::kMillisecond);
0177
0178
0179 void BM_INTERSECT_PLANES_SOA(benchmark::State& state) {
0180 using mask_t = mask<rectangle2D, algebra_v, std::uint_least16_t>;
0181 using vector3_t = dvector3D<algebra_v>;
0182
0183 auto dists = get_dists<algebra_v>(n_surfaces);
0184 auto [plane_descs, transforms] =
0185 test::planes_along_direction<algebra_v>(dists, vector3_t{1.f, 1.f, 1.f});
0186
0187 std::vector<mask_t> masks{};
0188 for (std::size_t i = 0u; i < plane_descs.size(); ++i) {
0189 masks.emplace_back(0u, 100.f, 200.f);
0190 }
0191
0192 const auto rays = generate_rays();
0193 const auto pi = ray_intersector<rectangle2D, algebra_v>{};
0194
0195 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0196 std::size_t hit{0u};
0197 std::size_t miss{0u};
0198 #endif
0199
0200 for (auto _ : state) {
0201 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0202 hit = 0u;
0203 miss = 0u;
0204 #endif
0205
0206
0207 for (const auto& ray : rays) {
0208 for (std::size_t i = 0u; i < plane_descs.size(); ++i) {
0209 auto is = pi(ray, plane_descs[i], masks[i], transforms[i]);
0210
0211 benchmark::DoNotOptimize(is);
0212
0213 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0214 hit += is.is_inside().count();
0215 miss += simd_size - is.is_inside().count();
0216 #endif
0217 }
0218 }
0219 }
0220
0221 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0222 DETRAY_INFO_HOST(mask_t::shape::name
0223 << " SoA: hit/miss ... " << hit << " / " << miss
0224 << " (total: " << rays.size() * masks.size() * simd_size
0225 << ")");
0226 #endif
0227 }
0228
0229 BENCHMARK(BM_INTERSECT_PLANES_SOA)
0230 #ifdef DETRAY_BENCHMARK_MULTITHREAD
0231 ->ThreadRange(1, benchmark::CPUInfo::Get().num_cpus)
0232 #endif
0233 ->Unit(benchmark::kMillisecond);
0234
0235
0236 void BM_INTERSECT_CYLINDERS_AOS(benchmark::State& state) {
0237 using transform3_t = dtransform3D<algebra_s>;
0238 using scalar_t = dscalar<algebra_s>;
0239
0240 using mask_t = mask<cylinder2D, algebra_s, std::uint_least16_t>;
0241
0242 std::vector<mask_t> masks;
0243 for (const scalar_t r : get_dists<algebra_s>(n_surfaces)) {
0244 masks.emplace_back(0u, r, -100.f, 100.f);
0245 }
0246
0247 transform3_t trf{};
0248
0249 mask_link_t mask_link{mask_id::e_conc_cylinder3, 0u};
0250 material_link_t material_link{material_id::e_material_slab, 0u};
0251 surface_desc_t cyl_desc(0u, mask_link, material_link, 0u,
0252 surface_id::e_sensitive);
0253
0254
0255 const auto rays = generate_rays();
0256 const auto cci = ray_intersector<cylinder2D, algebra_s>{};
0257 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0258 std::size_t hit{0u};
0259 std::size_t miss{0u};
0260 #endif
0261 for (auto _ : state) {
0262 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0263 hit = 0u;
0264 miss = 0u;
0265 #endif
0266
0267
0268 for (const auto& ray : rays) {
0269 for (const auto& cylinder : masks) {
0270 auto is = cci(ray, cyl_desc, cylinder, trf);
0271
0272 static_assert(is.size() == 2u, "Wrong number of solutions");
0273 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0274 for (const auto& i : is) {
0275 if (i.is_inside()) {
0276 ++hit;
0277 } else {
0278 ++miss;
0279 }
0280 }
0281 #endif
0282 benchmark::DoNotOptimize(is);
0283 }
0284 }
0285 }
0286 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0287 DETRAY_INFO_HOST(mask_t::shape::name
0288 << " AoS: hit/miss ... " << hit << " / " << miss
0289 << " (total: " << rays.size() * masks.size() << ")");
0290 #endif
0291 }
0292
0293 BENCHMARK(BM_INTERSECT_CYLINDERS_AOS)
0294 #ifdef DETRAY_BENCHMARK_MULTITHREAD
0295 ->ThreadRange(1, benchmark::CPUInfo::Get().num_cpus)
0296 #endif
0297 ->Unit(benchmark::kMillisecond);
0298
0299
0300 void BM_INTERSECT_CYLINDERS_SOA(benchmark::State& state) {
0301 using transform3_t = dtransform3D<algebra_v>;
0302 using scalar_t = dscalar<algebra_v>;
0303
0304 using mask_t = mask<cylinder2D, algebra_v, std::uint_least16_t>;
0305
0306 std::vector<mask_t> masks;
0307 for (const scalar_t r : get_dists<algebra_v>(n_surfaces)) {
0308 masks.emplace_back(0u, r, -100.f, 100.f);
0309 }
0310
0311 transform3_t trf{};
0312
0313 mask_link_t mask_link{mask_id::e_conc_cylinder3, 0u};
0314 material_link_t material_link{material_id::e_material_slab, 0u};
0315 surface_desc_t cyl_desc(0u, mask_link, material_link, 0u,
0316 surface_id::e_sensitive);
0317
0318
0319 const auto rays = generate_rays();
0320 const auto cci = ray_intersector<cylinder2D, algebra_v>{};
0321 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0322 std::size_t hit{0u};
0323 std::size_t miss{0u};
0324 #endif
0325 for (auto _ : state) {
0326 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0327 hit = 0u;
0328 miss = 0u;
0329 #endif
0330
0331
0332 for (const auto& ray : rays) {
0333 for (const auto& cylinder : masks) {
0334 auto is = cci(ray, cyl_desc, cylinder, trf);
0335
0336 static_assert(is.size() == 2u, "Wrong number of solutions");
0337 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0338 for (const auto& i : is) {
0339 hit += i.is_inside().count();
0340 miss += simd_size - i.is_inside().count();
0341 }
0342 #endif
0343 benchmark::DoNotOptimize(is);
0344 }
0345 }
0346 }
0347 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0348 DETRAY_INFO_HOST(mask_t::shape::name
0349 << " SoA: hit/miss ... " << hit << " / " << miss
0350 << " (total: " << rays.size() * masks.size() * simd_size
0351 << ")");
0352 #endif
0353 }
0354
0355 BENCHMARK(BM_INTERSECT_CYLINDERS_SOA)
0356 #ifdef DETRAY_BENCHMARK_MULTITHREAD
0357 ->ThreadRange(1, benchmark::CPUInfo::Get().num_cpus)
0358 #endif
0359 ->Unit(benchmark::kMillisecond);
0360
0361
0362 void BM_INTERSECT_CONCENTRIC_CYLINDERS_AOS(benchmark::State& state) {
0363 using transform3_t = dtransform3D<algebra_s>;
0364 using scalar_t = dscalar<algebra_s>;
0365
0366 using mask_t = mask<concentric_cylinder2D, algebra_s, std::uint_least16_t>;
0367
0368 std::vector<mask_t> masks;
0369 for (const scalar_t r : get_dists<algebra_s>(n_surfaces)) {
0370 masks.emplace_back(0u, r, -100.f, 100.f);
0371 }
0372
0373 transform3_t trf{};
0374
0375 mask_link_t mask_link{mask_id::e_conc_cylinder3, 0u};
0376 material_link_t material_link{material_id::e_material_slab, 0u};
0377 surface_desc_t cyl_desc(0u, mask_link, material_link, 0u,
0378 surface_id::e_sensitive);
0379
0380
0381 const auto rays = generate_rays();
0382 const auto cci = ray_intersector<concentric_cylinder2D, algebra_s>{};
0383 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0384 std::size_t hit{0u};
0385 std::size_t miss{0u};
0386 #endif
0387
0388 for (auto _ : state) {
0389 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0390 hit = 0u;
0391 miss = 0u;
0392 #endif
0393
0394 for (const auto& ray : rays) {
0395 for (const auto& cylinder : masks) {
0396 auto is = cci(ray, cyl_desc, cylinder, trf);
0397 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0398 if (is.is_inside()) {
0399 ++hit;
0400 } else {
0401 ++miss;
0402 }
0403 #endif
0404 benchmark::DoNotOptimize(is);
0405 }
0406 }
0407 }
0408 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0409 DETRAY_INFO_HOST(mask_t::shape::name
0410 << " AoS: hit/miss ... " << hit << " / " << miss
0411 << " (total: " << rays.size() * masks.size() << ")");
0412 #endif
0413 }
0414
0415 BENCHMARK(BM_INTERSECT_CONCENTRIC_CYLINDERS_AOS)
0416 #ifdef DETRAY_BENCHMARK_MULTITHREAD
0417 ->ThreadRange(1, benchmark::CPUInfo::Get().num_cpus)
0418 #endif
0419 ->Unit(benchmark::kMillisecond);
0420
0421
0422 void BM_INTERSECT_CONCENTRIC_CYLINDERS_SOA(benchmark::State& state) {
0423 using transform3_t = dtransform3D<algebra_v>;
0424 using scalar_t = dscalar<algebra_v>;
0425
0426 using mask_t = mask<concentric_cylinder2D, algebra_v, std::uint_least16_t>;
0427
0428 std::vector<mask_t> masks;
0429 for (const scalar_t r : get_dists<algebra_v>(n_surfaces)) {
0430 masks.emplace_back(0u, r, -100.f, 100.f);
0431 }
0432
0433 transform3_t trf{};
0434
0435 mask_link_t mask_link{mask_id::e_conc_cylinder3, 0u};
0436 material_link_t material_link{material_id::e_material_slab, 0u};
0437 surface_desc_t cyl_desc(0u, mask_link, material_link, 0u,
0438 surface_id::e_sensitive);
0439
0440
0441 const auto rays = generate_rays();
0442 const auto cci = ray_intersector<concentric_cylinder2D, algebra_v>{};
0443 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0444 std::size_t hit{0u};
0445 std::size_t miss{0u};
0446 #endif
0447 for (auto _ : state) {
0448 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0449 hit = 0u;
0450 miss = 0u;
0451 #endif
0452
0453 for (const auto& ray : rays) {
0454 for (const auto& cylinder : masks) {
0455 auto is = cci(ray, cyl_desc, cylinder, trf);
0456 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0457 hit += is.is_inside().count();
0458 miss += simd_size - is.is_inside().count();
0459 #endif
0460 benchmark::DoNotOptimize(is);
0461 }
0462 }
0463 }
0464 #ifdef DETRAY_BENCHMARK_PRINTOUTS
0465 DETRAY_INFO_HOST(mask_t::shape::name
0466 << " SoA: hit/miss ... " << hit << " / " << miss
0467 << " (total: " << rays.size() * masks.size() * simd_size
0468 << ")");
0469 #endif
0470 }
0471
0472 BENCHMARK(BM_INTERSECT_CONCENTRIC_CYLINDERS_SOA)
0473 #ifdef DETRAY_BENCHMARK_MULTITHREAD
0474 ->ThreadRange(1, benchmark::CPUInfo::Get().num_cpus)
0475 #endif
0476 ->Unit(benchmark::kMillisecond);