Skip to content

Commit c0d8f86

Browse files
authored
Add benchmarking for knn and knn nanoflann (#6267)
* Add benchmarking for knn and knn nanoflann * Knn benchmark fixes * Remove nans from the radiusSearch benchmark * Fix formatting. Fix cloud in organization. Fix to only use one argument since the other was ignored. --------- Co-authored-by: jmackay2 <jmackay2>
1 parent da64bf9 commit c0d8f86

File tree

2 files changed

+149
-28
lines changed

2 files changed

+149
-28
lines changed

benchmarks/CMakeLists.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ PCL_ADD_BENCHMARK(filters_radius_outlier_removal FILES filters/radius_outlier_re
2929
"${PCL_SOURCE_DIR}/test/milk_cartoon_all_small_clorox.pcd")
3030

3131
PCL_ADD_BENCHMARK(search_radius_search FILES search/radius_search.cpp
32-
LINK_WITH pcl_io pcl_search
33-
ARGUMENTS "${PCL_SOURCE_DIR}/test/table_scene_mug_stereo_textured.pcd"
34-
"${PCL_SOURCE_DIR}/test/milk_cartoon_all_small_clorox.pcd")
35-
32+
LINK_WITH pcl_io pcl_search pcl_filters
33+
ARGUMENTS "${PCL_SOURCE_DIR}/test/table_scene_mug_stereo_textured.pcd")
34+

benchmarks/search/radius_search.cpp

Lines changed: 146 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
#include <pcl/filters/filter.h>
12
#include <pcl/io/pcd_io.h>
3+
#include <pcl/search/kdtree.h>
4+
#include <pcl/search/kdtree_nanoflann.h>
25
#include <pcl/search/organized.h>
36
#include <pcl/point_cloud.h>
47
#include <pcl/point_types.h>
@@ -7,56 +10,175 @@
710

811
#include <chrono>
912

10-
static void
11-
BM_OrganizedNeighborSearch(benchmark::State& state, const std::string& file)
13+
void
14+
print_help()
1215
{
13-
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudIn(new pcl::PointCloud<pcl::PointXYZ>);
14-
pcl::PCDReader reader;
15-
reader.read(file, *cloudIn);
16+
std::cout << "Usage: benchmark_radius_search <pcd filename>\n";
17+
std::cout << "Additional argument options:\n";
18+
std::cout << "Usage: benchmark_radius_search <pcd filename> <radius search> "
19+
"<neighbor limit>\n";
20+
}
1621

22+
static void
23+
BM_OrganizedNeighborSearch(benchmark::State& state,
24+
const pcl::PointCloud<pcl::PointXYZ>::Ptr cloudIn,
25+
const double searchRadius,
26+
const size_t neighborLimit)
27+
{
1728
pcl::search::OrganizedNeighbor<pcl::PointXYZ> organizedNeighborSearch;
1829
organizedNeighborSearch.setInputCloud(cloudIn);
1930

20-
double radiusSearchTime = 0;
21-
std::vector<int> indices(cloudIn->size()); // Fixed indices from 0 to cloud size
22-
std::iota(indices.begin(), indices.end(), 0);
2331
int radiusSearchIdx = 0;
2432

33+
pcl::Indices k_indices;
34+
std::vector<float> k_sqr_distances;
2535
for (auto _ : state) {
26-
int searchIdx = indices[radiusSearchIdx++ % indices.size()];
27-
double searchRadius = 0.1; // or any fixed radius like 0.05
36+
state.PauseTiming();
37+
int searchIdx = radiusSearchIdx++ % cloudIn->size();
38+
while (!pcl::isFinite((*cloudIn)[searchIdx])) {
39+
searchIdx = radiusSearchIdx++ % cloudIn->size();
40+
}
41+
state.ResumeTiming();
42+
organizedNeighborSearch.radiusSearch(
43+
(*cloudIn)[searchIdx], searchRadius, k_indices, k_sqr_distances, neighborLimit);
44+
}
45+
}
2846

29-
pcl::Indices k_indices;
30-
std::vector<float> k_sqr_distances;
47+
static void
48+
BM_KdTree(benchmark::State& state,
49+
const pcl::PointCloud<pcl::PointXYZ>::Ptr cloudIn,
50+
const double searchRadius,
51+
const size_t neighborLimit)
52+
{
53+
pcl::search::KdTree<pcl::PointXYZ> kdtree(false);
54+
kdtree.setInputCloud(cloudIn);
3155

56+
int radiusSearchIdx = 0;
57+
58+
pcl::Indices k_indices;
59+
std::vector<float> k_sqr_distances;
60+
for (auto _ : state) {
61+
state.PauseTiming();
62+
int searchIdx = radiusSearchIdx++ % cloudIn->size();
63+
while (!pcl::isFinite((*cloudIn)[searchIdx])) {
64+
searchIdx = radiusSearchIdx++ % cloudIn->size();
65+
}
66+
state.ResumeTiming();
67+
kdtree.radiusSearch(
68+
searchIdx, searchRadius, k_indices, k_sqr_distances, neighborLimit);
69+
}
70+
}
71+
72+
static void
73+
BM_KdTreeAll(benchmark::State& state,
74+
const pcl::PointCloud<pcl::PointXYZ>::Ptr cloudIn,
75+
const double searchRadius,
76+
const size_t neighborLimit)
77+
{
78+
pcl::search::KdTree<pcl::PointXYZ> kdtree(false);
79+
kdtree.setInputCloud(cloudIn);
80+
81+
// Leaving indices empty to have it search through all points
82+
pcl::Indices indices;
83+
std::vector<pcl::Indices> k_indices;
84+
std::vector<std::vector<float>> k_sqr_distances;
85+
for (auto _ : state) {
3286
auto start_time = std::chrono::high_resolution_clock::now();
33-
organizedNeighborSearch.radiusSearch(
34-
(*cloudIn)[searchIdx], searchRadius, k_indices, k_sqr_distances);
87+
kdtree.radiusSearch(
88+
*cloudIn, indices, searchRadius, k_indices, k_sqr_distances, neighborLimit);
3589
auto end_time = std::chrono::high_resolution_clock::now();
36-
37-
radiusSearchTime +=
38-
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time)
39-
.count();
90+
std::chrono::duration<double> elapsed = end_time - start_time;
91+
state.SetIterationTime(elapsed.count() / cloudIn->size());
4092
}
4193

42-
state.SetItemsProcessed(state.iterations());
43-
state.SetIterationTime(
44-
radiusSearchTime /
45-
(state.iterations() * indices.size())); // Normalize by total points processed
94+
state.SetItemsProcessed(cloudIn->size());
95+
}
96+
97+
#if PCL_HAS_NANOFLANN
98+
static void
99+
BM_KdTreeNanoflann(benchmark::State& state,
100+
const pcl::PointCloud<pcl::PointXYZ>::Ptr cloudIn,
101+
const double searchRadius,
102+
const size_t neighborLimit)
103+
{
104+
pcl::search::KdTreeNanoflann<pcl::PointXYZ> kdtree;
105+
kdtree.setInputCloud(cloudIn);
106+
107+
int radiusSearchIdx = 0;
108+
109+
pcl::Indices k_indices;
110+
std::vector<float> k_sqr_distances;
111+
for (auto _ : state) {
112+
state.PauseTiming();
113+
int searchIdx = radiusSearchIdx++ % cloudIn->size();
114+
while (!pcl::isFinite((*cloudIn)[searchIdx])) {
115+
searchIdx = radiusSearchIdx++ % cloudIn->size();
116+
}
117+
state.ResumeTiming();
118+
kdtree.radiusSearch(
119+
searchIdx, searchRadius, k_indices, k_sqr_distances, neighborLimit);
120+
}
46121
}
122+
#endif
47123

48124
int
49125
main(int argc, char** argv)
50126
{
51127
if (argc < 2) {
52128
std::cerr << "No test file given. Please provide a PCD file for the benchmark."
53129
<< std::endl;
130+
print_help();
54131
return -1;
55132
}
56133

134+
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudIn(new pcl::PointCloud<pcl::PointXYZ>);
135+
pcl::PCDReader reader;
136+
reader.read(argv[1], *cloudIn);
137+
138+
// Filter out nans
139+
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFiltered(new pcl::PointCloud<pcl::PointXYZ>);
140+
pcl::Indices indices;
141+
pcl::removeNaNFromPointCloud(*cloudIn, *cloudFiltered, indices);
142+
143+
double searchRadius = 0.1;
144+
if (argc > 2) {
145+
try {
146+
searchRadius = std::abs(std::stod(argv[2]));
147+
} catch (const std::invalid_argument&) {
148+
std::cerr << "Error: Invalid search radius. Setting it to a default of 0.1."
149+
<< std::endl;
150+
}
151+
}
152+
153+
size_t neighborLimit = 0u;
154+
if (argc > 3) {
155+
try {
156+
neighborLimit = std::stoul(argv[3]);
157+
} catch (const std::invalid_argument&) {
158+
std::cerr << "Error: Invalid neighbor limit. Setting it to a default of int max."
159+
<< std::endl;
160+
}
161+
}
162+
163+
benchmark::RegisterBenchmark("OrganizedNeighborSearch",
164+
&BM_OrganizedNeighborSearch,
165+
cloudIn,
166+
searchRadius,
167+
neighborLimit)
168+
->Unit(benchmark::kMicrosecond);
169+
benchmark::RegisterBenchmark(
170+
"KdTree", &BM_KdTree, cloudIn, searchRadius, neighborLimit)
171+
->Unit(benchmark::kMicrosecond);
172+
benchmark::RegisterBenchmark(
173+
"KdTreeAll", &BM_KdTreeAll, cloudFiltered, searchRadius, neighborLimit)
174+
->Unit(benchmark::kMicrosecond)
175+
->UseManualTime()
176+
->Iterations(1);
177+
#if PCL_HAS_NANOFLANN
57178
benchmark::RegisterBenchmark(
58-
"BM_OrganizedNeighborSearch", &BM_OrganizedNeighborSearch, argv[1])
59-
->Unit(benchmark::kMillisecond);
179+
"KdTreeNanoflann", &BM_KdTreeNanoflann, cloudIn, searchRadius, neighborLimit)
180+
->Unit(benchmark::kMicrosecond);
181+
#endif
60182
benchmark::Initialize(&argc, argv);
61183
benchmark::RunSpecifiedBenchmarks();
62184
}

0 commit comments

Comments
 (0)