-
Notifications
You must be signed in to change notification settings - Fork 34
/
bvh_driver.cpp
300 lines (265 loc) · 10.4 KB
/
bvh_driver.cpp
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
/****************************************************************************
* Copyright (c) 2017-2022 by the ArborX authors *
* All rights reserved. *
* *
* This file is part of the ArborX library. ArborX is *
* distributed under a BSD 3-clause license. For the licensing terms see *
* the LICENSE file in the top-level directory. *
* *
* SPDX-License-Identifier: BSD-3-Clause *
****************************************************************************/
#include <ArborX_BoostRTreeHelpers.hpp>
#include <ArborX_LinearBVH.hpp>
#include <ArborX_Version.hpp>
#include <Kokkos_Core.hpp>
#include <boost/program_options.hpp>
#include <cstdlib>
#include <iostream>
#include "benchmark_registration.hpp"
#include <point_clouds.hpp>
#ifdef ARBORX_PERFORMANCE_TESTING
#include <mpi.h>
#endif
#include <benchmark/benchmark.h>
template <typename ExecutionSpace, typename TreeType>
struct BenchmarkRegistration
{
BenchmarkRegistration(Spec const &, std::string const &) {}
};
template <typename ExecutionSpace, typename MemorySpace>
struct BenchmarkRegistration<ExecutionSpace, ArborX::BVH<MemorySpace>>
{
using TreeType = ArborX::BVH<MemorySpace>;
BenchmarkRegistration(Spec const &spec, std::string const &description)
{
register_benchmark_construction<ExecutionSpace, TreeType>(spec,
description);
register_benchmark_spatial_query_no_callback<ExecutionSpace, TreeType>(
spec, description);
register_benchmark_spatial_query_callback<ExecutionSpace, TreeType>(
spec, description);
register_benchmark_nearest_query_no_callback<ExecutionSpace, TreeType>(
spec, description);
register_benchmark_nearest_query_callback<ExecutionSpace, TreeType>(
spec, description);
}
};
template <typename ExecutionSpace>
struct BenchmarkRegistration<ExecutionSpace, BoostExt::RTree<ArborX::Point>>
{
using TreeType = BoostExt::RTree<ArborX::Point>;
BenchmarkRegistration(Spec const &spec, std::string const &description)
{
register_benchmark_construction<ExecutionSpace, TreeType>(spec,
description);
register_benchmark_spatial_query_no_callback<ExecutionSpace, TreeType>(
spec, description);
register_benchmark_nearest_query_no_callback<ExecutionSpace, TreeType>(
spec, description);
}
};
template <typename ExecutionSpace>
using BVHBenchmarkRegistration =
BenchmarkRegistration<ExecutionSpace,
ArborX::BVH<typename ExecutionSpace::memory_space>>;
void register_bvh_benchmarks(Spec const &spec)
{
#ifdef KOKKOS_ENABLE_SERIAL
if (spec.backends == "all" || spec.backends == "serial")
BVHBenchmarkRegistration<Kokkos::Serial>(spec, "ArborX::BVH<Serial>");
#else
if (spec.backends == "serial")
throw std::runtime_error("Serial backend not available!");
#endif
#ifdef KOKKOS_ENABLE_OPENMP
if (spec.backends == "all" || spec.backends == "openmp")
BVHBenchmarkRegistration<Kokkos::OpenMP>(spec, "ArborX::BVH<OpenMP>");
#else
if (spec.backends == "openmp")
throw std::runtime_error("OpenMP backend not available!");
#endif
#ifdef KOKKOS_ENABLE_THREADS
if (spec.backends == "all" || spec.backends == "threads")
BVHBenchmarkRegistration<Kokkos::Threads>(spec, "ArborX::BVH<Threads>");
#else
if (spec.backends == "threads")
throw std::runtime_error("Threads backend not available!");
#endif
#ifdef KOKKOS_ENABLE_CUDA
if (spec.backends == "all" || spec.backends == "cuda")
BVHBenchmarkRegistration<Kokkos::Cuda>(spec, "ArborX::BVH<Cuda>");
#else
if (spec.backends == "cuda")
throw std::runtime_error("CUDA backend not available!");
#endif
#ifdef KOKKOS_ENABLE_HIP
if (spec.backends == "all" || spec.backends == "hip")
BVHBenchmarkRegistration<Kokkos::HIP>(spec, "ArborX::BVH<HIP>");
#else
if (spec.backends == "hip")
throw std::runtime_error("HIP backend not available!");
#endif
#ifdef KOKKOS_ENABLE_OPENMPTARGET
if (spec.backends == "all" || spec.backends == "openmptarget")
BVHBenchmarkRegistration<Kokkos::Experimental::OpenMPTarget>(
spec, "ArborX::BVH<OpenMPTarget>");
#else
if (spec.backends == "openmptarget")
throw std::runtime_error("OpenMPTarget backend not available!");
#endif
#ifdef KOKKOS_ENABLE_SYCL
if (spec.backends == "all" || spec.backends == "sycl")
BVHBenchmarkRegistration<Kokkos::Experimental::SYCL>(spec,
"ArborX::BVH<SYCL>");
#else
if (spec.backends == "sycl")
throw std::runtime_error("SYCL backend not available!");
#endif
}
void register_boostrtree_benchmarks(Spec const &spec)
{
#ifdef KOKKOS_ENABLE_SERIAL
if (spec.backends == "all" || spec.backends == "rtree")
BenchmarkRegistration<Kokkos::Serial, BoostExt::RTree<ArborX::Point>>(
spec, "BoostRTree");
#else
std::ignore = spec;
#endif
}
// NOTE Motivation for this class that stores the argument count and values is
// I could not figure out how to make the parser consume arguments with
// Boost.Program_options
// Benchmark removes its own arguments from the command line arguments. This
// means, that by virtue of returning references to internal data members in
// argc() and argv() function, it will necessarily modify the members. It will
// decrease _argc, and "reduce" _argv data. Hence, we must keep a copy of _argv
// that is not modified from the outside to release memory in the destructor
// correctly.
class CmdLineArgs
{
private:
int _argc;
std::vector<char *> _argv;
std::vector<char *> _owner_ptrs;
public:
CmdLineArgs(std::vector<std::string> const &args, char const *exe)
: _argc(args.size() + 1)
, _owner_ptrs{new char[std::strlen(exe) + 1]}
{
std::strcpy(_owner_ptrs[0], exe);
_owner_ptrs.reserve(_argc);
for (auto const &s : args)
{
_owner_ptrs.push_back(new char[s.size() + 1]);
std::strcpy(_owner_ptrs.back(), s.c_str());
}
_argv = _owner_ptrs;
}
~CmdLineArgs()
{
for (auto *p : _owner_ptrs)
{
delete[] p;
}
}
int &argc() { return _argc; }
char **argv() { return _argv.data(); }
};
int main(int argc, char *argv[])
{
#ifdef ARBORX_PERFORMANCE_TESTING
MPI_Init(&argc, &argv);
#endif
Kokkos::initialize(argc, argv);
namespace bpo = boost::program_options;
bpo::options_description desc("Allowed options");
Spec single_spec;
std::string source_pt_cloud;
std::string target_pt_cloud;
std::vector<std::string> exact_specs;
// clang-format off
desc.add_options()
( "help", "produce help message" )
( "values", bpo::value<int>(&single_spec.n_values)->default_value(50000), "number of indexable values (source)" )
( "queries", bpo::value<int>(&single_spec.n_queries)->default_value(20000), "number of queries (target)" )
( "predicate-sort", bpo::value<bool>(&single_spec.sort_predicates)->default_value(true), "sort predicates" )
( "neighbors", bpo::value<int>(&single_spec.n_neighbors)->default_value(10), "desired number of results per query" )
( "buffer", bpo::value<int>(&single_spec.buffer_size)->default_value(0), "size for buffer optimization in radius search" )
( "source-point-cloud-type", bpo::value<std::string>(&source_pt_cloud)->default_value("filled_box"), "shape of the source point cloud" )
( "target-point-cloud-type", bpo::value<std::string>(&target_pt_cloud)->default_value("filled_box"), "shape of the target point cloud" )
( "exact-spec", bpo::value<std::vector<std::string>>(&exact_specs)->multitoken(), "exact specification (can be specified multiple times for batch)" )
;
// clang-format on
bpo::variables_map vm;
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
.options(desc)
.allow_unregistered()
.run();
bpo::store(parsed, vm);
CmdLineArgs pass_further{
bpo::collect_unrecognized(parsed.options, bpo::include_positional),
argv[0]};
bpo::notify(vm);
std::cout << "ArborX version: " << ArborX::version() << std::endl;
std::cout << "ArborX hash : " << ArborX::gitCommitHash() << std::endl;
std::cout << "Kokkos version: " << ArborX::Details::KokkosExt::version()
<< std::endl;
if (vm.count("help") > 0)
{
// Full list of options consists of Kokkos + Boost.Program_options +
// Google Benchmark and we still need to call benchmark::Initialize() to
// get those printed to the standard output.
std::cout << desc << "\n";
int ac = 2;
char *av[] = {(char *)"ignored", (char *)"--help"};
// benchmark::Initialize() calls exit(0) when `--help` so register
// Kokkos::finalize() to be called on normal program termination.
std::atexit(Kokkos::finalize);
benchmark::Initialize(&ac, av);
return 1;
}
if (vm.count("exact-spec") > 0)
{
for (std::string option :
{"values", "queries", "predicate-sort", "neighbors", "buffer",
"source-point-cloud-type", "target-point-cloud-type"})
{
if (!vm[option].defaulted())
{
std::cout << "Conflicting options: 'exact-spec' and '" << option
<< "', exiting..." << std::endl;
return EXIT_FAILURE;
}
}
}
benchmark::Initialize(&pass_further.argc(), pass_further.argv());
// Throw if some of the arguments have not been recognized.
std::ignore =
bpo::command_line_parser(pass_further.argc(), pass_further.argv())
.options(bpo::options_description(""))
.run();
std::vector<Spec> specs;
specs.reserve(exact_specs.size());
for (auto const &spec_string : exact_specs)
specs.emplace_back(spec_string);
if (vm.count("exact-spec") == 0)
{
single_spec.backends = "all";
single_spec.source_point_cloud_type =
ArborXBenchmark::to_point_cloud_enum(source_pt_cloud);
single_spec.target_point_cloud_type =
ArborXBenchmark::to_point_cloud_enum(target_pt_cloud);
specs.push_back(single_spec);
}
for (auto const &spec : specs)
{
register_bvh_benchmarks(spec);
register_boostrtree_benchmarks(spec);
}
benchmark::RunSpecifiedBenchmarks();
Kokkos::finalize();
#ifdef ARBORX_PERFORMANCE_TESTING
MPI_Finalize();
#endif
return EXIT_SUCCESS;
}