From b3b137a4250ceb72724e1ff265cd9bef84b4ba65 Mon Sep 17 00:00:00 2001
From: stelzo
Date: Mon, 13 May 2024 17:40:19 +0200
Subject: [PATCH] Memopt (#17)
* remove Vec creation in byte conversions
* par par
* opti with byte similar
* clippy
* intro docs
* translations
* idiomatic
* fix par docs
* fix rosrust conv
* fix msg conv
---
Cargo.toml | 5 +-
README.md | 22 +-
benches/roundtrip.rs | 589 ++++++++++++++++++++--
examples/custom_enum_field_filter.rs | 79 +--
rpcl2_derive/Cargo.toml | 4 +-
rpcl2_derive/src/lib.rs | 179 ++++---
src/convert.rs | 256 +++++-----
src/iterator.rs | 32 +-
src/lib.rs | 707 +++++++++++++++++++--------
src/points.rs | 90 ++--
src/prelude.rs | 2 +-
src/ros_types.rs | 66 ++-
tests/e2e_test.rs | 12 +-
13 files changed, 1493 insertions(+), 550 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 3483be9..cfa998a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -51,4 +51,7 @@ rayon = ["dep:rayon"]
derive = ["dep:rpcl2_derive", "dep:type-layout"]
nalgebra = ["dep:nalgebra"]
-default = ["rayon", "derive", "nalgebra"]
\ No newline at end of file
+default = ["derive"]
+
+[package.metadata.docs.rs]
+rustdoc-args = ["--generate-link-to-definition"]
diff --git a/README.md b/README.md
index 7143c6c..8c4a8d1 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,20 @@
## !! Note !!
+
This library is currently in development for v1.0.0, for the documentation of v0.4.0 on crates.io, visit the [docs](https://docs.rs/ros_pointcloud2/0.4.0/ros_pointcloud2/).
ROS PointCloud2
- A complete and versatile abstraction of PointCloud2.
+ A PointCloud2 message conversion library.
-To keep the crate a general purpose library for the problem, it uses its own type for the message `PointCloud2Msg`.
-ROS1 and ROS2 is supported with feature flags.
+ros_pointcloud2 uses its own type for the message `PointCloud2Msg` to keep the library framework agnostic. ROS1 and ROS2 are supported with feature flags.
Get started with the example below, check out the other use cases in the `examples` folder or see the [Documentation](https://docs.rs/ros_pointcloud2/1.0.0/ros_pointcloud2/) for a complete guide.
## Quickstart
-The following example uses the iterator APIs. For memory bound pipelines, you may also try the `try_from_vec` or `try_into_vec` functions by enabling the `derive` feature.
-
```rust
use ros_pointcloud2::prelude::*;
@@ -27,7 +25,7 @@ let cloud_points = vec![
];
// Give the Vec or anything that implements `IntoIterator`.
-let in_msg = PointCloud2Msg::try_from_iter(cloud_points).unwrap();
+let in_msg = PointCloud2Msg::try_from_vec(cloud_points).unwrap();
// Convert the ROS crate message type, we will use r2r here.
// let msg: r2r::sensor_msgs::msg::PointCloud2 = in_msg.into();
@@ -36,7 +34,7 @@ let in_msg = PointCloud2Msg::try_from_iter(cloud_points).unwrap();
// let in_msg: PointCloud2Msg = msg.into();
let new_pcl = in_msg.try_into_iter().unwrap()
- .map(|point: PointXYZ| { // Define the type of point here.
+ .map(|point: PointXYZ| { // Define the info you want to have from the Msg.
// Some logic here ...
point
@@ -84,7 +82,15 @@ Also, indicate the following dependencies to your linker inside the `package.xml
builtin_interfaces
```
-Please open an issue or PR if you want to see support for other crates.
+Please open an issue or PR if you need other integrations.
+
+## Performance
+
+The library offers a speed up when compared to PointCloudLibrary (PCL) conversions but the specific factor depends heavily on the use case and system.
+`vec` conversions are on average ~7.5x faster than PCL while the single core iteration `_iter` APIs are around 2x faster.
+Parallelization with `_par_iter` showcases a 10.5x speed up compared to an OpenMP accelerated PCL pipeline.
+
+The full benchmarks are publicly available in this [repository](https://github.com/stelzo/ros_pcl_conv_bench).
## License
diff --git a/benches/roundtrip.rs b/benches/roundtrip.rs
index cf4945b..afe4473 100644
--- a/benches/roundtrip.rs
+++ b/benches/roundtrip.rs
@@ -3,32 +3,174 @@ use ros_pointcloud2::prelude::*;
use rand::Rng;
-pub fn generate_random_pointcloud(num_points: usize, min: f32, max: f32) -> Vec {
+pub type PointXYZB = PointXYZINormal;
+
+pub fn distance_to_origin(point: &PointXYZ) -> f32 {
+ ((point.x.powi(2)) + (point.y.powi(2)) + (point.z.powi(2))).sqrt()
+}
+
+pub fn dot_product(point1: &PointXYZ, point2: &PointXYZ) -> f32 {
+ point1.x * point2.x + point1.y * point2.y + point1.z * point2.z
+}
+
+pub fn cross_product(point1: &PointXYZ, point2: &PointXYZ) -> PointXYZ {
+ PointXYZ {
+ x: point1.y * point2.z - point1.z * point2.y,
+ y: point1.z * point2.x - point1.x * point2.z,
+ z: point1.x * point2.y - point1.y * point2.x,
+ }
+}
+
+pub fn scalar_multiply(point: &PointXYZ, scalar: f32) -> PointXYZ {
+ PointXYZ {
+ x: point.x * scalar,
+ y: point.y * scalar,
+ z: point.z * scalar,
+ }
+}
+
+pub fn magnitude_squared(point: &PointXYZ) -> f32 {
+ (point.x.powi(2)) + (point.y.powi(2)) + (point.z.powi(2))
+}
+
+pub fn reflection_through_plane(
+ point: &PointXYZ,
+ normal: &PointXYZ,
+ point_on_plane: &PointXYZ,
+) -> PointXYZ {
+ PointXYZ {
+ x: point.x
+ - 2.0
+ * ((point.x - point_on_plane.x) * normal.x
+ + (point.y - point_on_plane.y) * normal.y
+ + (point.z - point_on_plane.z) * normal.z),
+ y: point.y
+ - 2.0
+ * ((point.x - point_on_plane.x) * normal.x
+ + (point.y - point_on_plane.y) * normal.y
+ + (point.z - point_on_plane.z) * normal.z),
+ z: point.z
+ - 2.0
+ * ((point.x - point_on_plane.x) * normal.x
+ + (point.y - point_on_plane.y) * normal.y
+ + (point.z - point_on_plane.z) * normal.z),
+ }
+}
+
+pub fn rotation_about_x(point: &PointXYZ, angle: f32) -> PointXYZ {
+ let c = f32::cos(angle);
+ let s = f32::sin(angle);
+ PointXYZ {
+ x: point.x,
+ y: point.y * c - point.z * s,
+ z: point.y * s + point.z * c,
+ }
+}
+
+pub fn closest_point_on_line(
+ point: &PointXYZ,
+ line_point: &PointXYZ,
+ line_direction: &PointXYZ,
+) -> PointXYZ {
+ PointXYZ {
+ x: line_point.x
+ + (line_point.x - point.x) * ((line_point.x - point.x).powi(2))
+ / ((line_direction.x * 2.0).powi(2))
+ + (line_direction.y * 2.0) * (point.z - line_point.z)
+ / ((line_direction.z * 2.0).powi(2)),
+ y: line_point.y
+ + (line_point.y - point.y) * ((line_point.y - point.y).powi(2))
+ / ((line_direction.y * 2.0).powi(2))
+ + (line_direction.x * 2.0) * (point.x - line_point.x)
+ / ((line_direction.x * 2.0).powi(2)),
+ z: line_point.z
+ + (line_point.z - point.z) * ((line_point.z - point.z).powi(2))
+ / ((line_direction.z * 2.0).powi(2))
+ + (line_direction.y * 2.0) * (point.y - line_point.y)
+ / ((line_direction.y * 2.0).powi(2)),
+ }
+}
+
+fn minus(point1: &PointXYZ, point2: &PointXYZ) -> PointXYZ {
+ PointXYZ {
+ x: point1.x - point2.x,
+ y: point1.y - point2.y,
+ z: point1.z - point2.z,
+ }
+}
+
+pub fn generate_random_pointcloud(num_points: usize, min: f32, max: f32) -> Vec {
let mut rng = rand::thread_rng();
let mut pointcloud = Vec::with_capacity(num_points);
for _ in 0..num_points {
- let point = PointXYZ {
+ let point = PointXYZB {
x: rng.gen_range(min..max),
y: rng.gen_range(min..max),
z: rng.gen_range(min..max),
+ ..Default::default()
};
pointcloud.push(point);
}
pointcloud
}
+pub fn heavy_computing(point: &PointXYZ, iterations: u32) -> f32 {
+ let mut result = distance_to_origin(point);
+ for _ in 0..iterations {
+ result += dot_product(
+ point,
+ &PointXYZ {
+ x: 1.0,
+ y: 2.0,
+ z: 3.0,
+ },
+ );
+ result += cross_product(
+ point,
+ &PointXYZ {
+ x: 4.0,
+ y: 5.0,
+ z: 6.0,
+ },
+ )
+ .x;
+ result = result + (result * 10.0).sqrt();
+ let reflected_point = reflection_through_plane(
+ point,
+ &PointXYZ {
+ x: 7.0,
+ y: 8.0,
+ z: 9.0,
+ },
+ &PointXYZ {
+ x: 3.0,
+ y: 4.0,
+ z: 5.0,
+ },
+ );
+ let rotated_point = rotation_about_x(
+ &PointXYZ {
+ x: 10.0,
+ y: 11.0,
+ z: 12.0,
+ },
+ std::f32::consts::PI / 2.0,
+ );
+
+ result += magnitude_squared(&minus(&reflected_point, &rotated_point));
+ }
+ result
+}
+
#[cfg(feature = "derive")]
-fn roundtrip_vec(cloud: Vec) -> bool {
+fn roundtrip_vec(cloud: Vec) -> bool {
let orig_len = cloud.len();
let internal_msg = PointCloud2Msg::try_from_vec(cloud).unwrap();
- let total = internal_msg
- .try_into_iter()
- .unwrap()
- .collect::>();
+ let total: Vec = internal_msg.try_into_vec().unwrap();
orig_len == total.len()
}
-fn roundtrip(cloud: Vec) -> bool {
+fn roundtrip(cloud: Vec) -> bool {
let orig_len = cloud.len();
let internal_msg = PointCloud2Msg::try_from_iter(cloud).unwrap();
let total = internal_msg
@@ -39,15 +181,13 @@ fn roundtrip(cloud: Vec) -> bool {
}
#[cfg(feature = "derive")]
-fn roundtrip_filter_vec(cloud: Vec) -> bool {
+fn roundtrip_filter_vec(cloud: Vec) -> bool {
let orig_len = cloud.len();
let internal_msg = PointCloud2Msg::try_from_vec(cloud).unwrap();
let total = internal_msg
.try_into_iter()
.unwrap()
- .filter(|point: &PointXYZ| {
- (point.x.powi(2) + point.y.powi(2) + point.z.powi(2)).sqrt() < 1.9
- })
+ .filter(|point: &PointXYZ| distance_to_origin(point) < 69.9)
.fold(PointXYZ::default(), |acc, point| PointXYZ {
x: acc.x + point.x,
y: acc.y + point.y,
@@ -56,15 +196,13 @@ fn roundtrip_filter_vec(cloud: Vec) -> bool {
orig_len == total.x as usize
}
-fn roundtrip_filter(cloud: Vec) -> bool {
+fn roundtrip_filter(cloud: Vec) -> bool {
let orig_len = cloud.len();
let internal_msg = PointCloud2Msg::try_from_iter(cloud).unwrap();
let total = internal_msg
.try_into_iter()
.unwrap()
- .filter(|point: &PointXYZ| {
- (point.x.powi(2) + point.y.powi(2) + point.z.powi(2)).sqrt() < 1.9
- })
+ .filter(|point: &PointXYZ| distance_to_origin(point) < 69.9)
.fold(PointXYZ::default(), |acc, point| PointXYZ {
x: acc.x + point.x,
y: acc.y + point.y,
@@ -73,8 +211,52 @@ fn roundtrip_filter(cloud: Vec) -> bool {
orig_len == total.x as usize
}
+fn roundtrip_computing(cloud: Vec) -> bool {
+ let internal_msg = PointCloud2Msg::try_from_iter(cloud).unwrap();
+ let total = internal_msg
+ .try_into_iter()
+ .unwrap()
+ .map(|point: PointXYZ| heavy_computing(&point, 100))
+ .sum::();
+ total > 0.0
+}
+
#[cfg(feature = "rayon")]
-fn roundtrip_par(cloud: Vec) -> bool {
+fn roundtrip_computing_par(cloud: Vec) -> bool {
+ let internal_msg = PointCloud2Msg::try_from_iter(cloud).unwrap();
+ let total = internal_msg
+ .try_into_par_iter()
+ .unwrap()
+ .map(|point: PointXYZ| heavy_computing(&point, 100))
+ .sum::();
+ total > 0.0
+}
+
+#[cfg(feature = "rayon")]
+fn roundtrip_computing_par_par(cloud: Vec) -> bool {
+ let internal_msg = PointCloud2Msg::try_from_par_iter(cloud.into_par_iter()).unwrap();
+ let total = internal_msg
+ .try_into_par_iter()
+ .unwrap()
+ .map(|point: PointXYZ| heavy_computing(&point, 100))
+ .sum::();
+ total > 0.0
+}
+
+#[cfg(feature = "derive")]
+fn roundtrip_computing_vec(cloud: Vec) -> bool {
+ let internal_msg = PointCloud2Msg::try_from_vec(cloud).unwrap();
+ let total: f32 = internal_msg
+ .try_into_vec()
+ .unwrap()
+ .into_iter()
+ .map(|point: PointXYZ| heavy_computing(&point, 100))
+ .sum();
+ total > 0.0
+}
+
+#[cfg(feature = "rayon")]
+fn roundtrip_par(cloud: Vec) -> bool {
let orig_len = cloud.len();
let internal_msg = PointCloud2Msg::try_from_iter(cloud).unwrap();
let total = internal_msg
@@ -85,15 +267,40 @@ fn roundtrip_par(cloud: Vec) -> bool {
}
#[cfg(feature = "rayon")]
-fn roundtrip_filter_par(cloud: Vec) -> bool {
+fn roundtrip_par_par(cloud: Vec) -> bool {
+ let orig_len = cloud.len();
+ let internal_msg = PointCloud2Msg::try_from_par_iter(cloud.into_par_iter()).unwrap();
+ let total = internal_msg
+ .try_into_par_iter()
+ .unwrap()
+ .collect::>();
+ orig_len != total.len()
+}
+
+#[cfg(feature = "rayon")]
+fn roundtrip_filter_par(cloud: Vec) -> bool {
let orig_len: usize = cloud.len();
let internal_msg = PointCloud2Msg::try_from_iter(cloud).unwrap();
let total = internal_msg
.try_into_par_iter()
.unwrap()
- .filter(|point: &PointXYZ| {
- (point.x.powi(2) + point.y.powi(2) + point.z.powi(2)).sqrt() < 1.9
- })
+ .filter(|point: &PointXYZ| distance_to_origin(point) < 69.9)
+ .reduce(PointXYZ::default, |acc, point| PointXYZ {
+ x: acc.x + point.x,
+ y: acc.y + point.y,
+ z: acc.z + point.z,
+ });
+ orig_len == total.x as usize
+}
+
+#[cfg(feature = "rayon")]
+fn roundtrip_filter_par_par(cloud: Vec) -> bool {
+ let orig_len: usize = cloud.len();
+ let internal_msg = PointCloud2Msg::try_from_par_iter(cloud.into_par_iter()).unwrap();
+ let total = internal_msg
+ .try_into_par_iter()
+ .unwrap()
+ .filter(|point: &PointXYZ| distance_to_origin(point) < 69.9)
.reduce(PointXYZ::default, |acc, point| PointXYZ {
x: acc.x + point.x,
y: acc.y + point.y,
@@ -103,61 +310,385 @@ fn roundtrip_filter_par(cloud: Vec) -> bool {
}
fn roundtrip_benchmark(c: &mut Criterion) {
+ let cloud_points_16k = generate_random_pointcloud(16_000, f32::MIN / 2.0, f32::MAX / 2.0);
+ let cloud_points_60k = generate_random_pointcloud(60_000, f32::MIN / 2.0, f32::MAX / 2.0);
+ let cloud_points_120k = generate_random_pointcloud(120_000, f32::MIN / 2.0, f32::MAX / 2.0);
let cloud_points_500k = generate_random_pointcloud(500_000, f32::MIN / 2.0, f32::MAX / 2.0);
let cloud_points_1_5m = generate_random_pointcloud(1_500_000, f32::MIN / 2.0, f32::MAX / 2.0);
- c.bench_function("roundtrip 500k", |b| {
+ // 16k points (Velodyne with 16 beams)
+
+ // Moving memory
+ c.bench_function("16k iter", |b| {
+ b.iter(|| {
+ black_box(roundtrip(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("16k iter_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("16k iter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par_par(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("16k vec", |b| {
+ b.iter(|| {
+ black_box(roundtrip_vec(cloud_points_16k.clone()));
+ })
+ });
+
+ // Simple distance filter
+ c.bench_function("16k iter_filter", |b| {
+ b.iter(|| {
+ roundtrip_filter(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("16k filter_par", |b| {
+ b.iter(|| {
+ roundtrip_filter_par(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("16k filter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_filter_par_par(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("16k vec_filter", |b| {
+ b.iter(|| {
+ roundtrip_filter_vec(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ // Heavy computing
+ c.bench_function("16k iter_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("16k iter_compute_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("16k iter_compute_par_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par_par(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("16k vec_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing_vec(black_box(cloud_points_16k.clone()));
+ })
+ });
+
+ // 60k points (Ouster with 64 beams)
+
+ // Moving memory
+ c.bench_function("60k iter", |b| {
+ b.iter(|| {
+ black_box(roundtrip(cloud_points_60k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("60k iter_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par(cloud_points_60k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("60k iter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par_par(cloud_points_60k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("60k vec", |b| {
+ b.iter(|| {
+ black_box(roundtrip_vec(cloud_points_60k.clone()));
+ })
+ });
+
+ // 120k points (Ouster with 128 beams)
+
+ // Moving memory
+ c.bench_function("120k iter", |b| {
+ b.iter(|| {
+ black_box(roundtrip(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("120k iter_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("120k iter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par_par(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("120k vec", |b| {
+ b.iter(|| {
+ black_box(roundtrip_vec(cloud_points_120k.clone()));
+ })
+ });
+
+ // Simple distance filter
+ c.bench_function("120k iter_filter", |b| {
+ b.iter(|| {
+ roundtrip_filter(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("120k filter_par", |b| {
+ b.iter(|| {
+ roundtrip_filter_par(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("120k filter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_filter_par_par(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("120k vec_filter", |b| {
+ b.iter(|| {
+ roundtrip_filter_vec(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ // Heavy computing
+ c.bench_function("120k iter_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("120k iter_compute_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("120k iter_compute_par_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par_par(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("120k vec_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing_vec(black_box(cloud_points_120k.clone()));
+ })
+ });
+
+ // 500k points (just to show how it scales)
+
+ // Moving memory
+ c.bench_function("500k iter", |b| {
b.iter(|| {
black_box(roundtrip(cloud_points_500k.clone()));
})
});
#[cfg(feature = "rayon")]
- c.bench_function("roundtrip_par 500k", |b| {
+ c.bench_function("500k iter_par", |b| {
b.iter(|| {
black_box(roundtrip_par(cloud_points_500k.clone()));
})
});
+ #[cfg(feature = "rayon")]
+ c.bench_function("500k iter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par_par(cloud_points_500k.clone()));
+ })
+ });
+
#[cfg(feature = "derive")]
- c.bench_function("roundtrip_vec 500k", |b| {
+ c.bench_function("500k vec", |b| {
b.iter(|| {
black_box(roundtrip_vec(cloud_points_500k.clone()));
})
});
- c.bench_function("roundtrip_filter 500k", |b| {
+ // Simple distance filter
+ c.bench_function("500k iter_filter", |b| {
b.iter(|| {
roundtrip_filter(black_box(cloud_points_500k.clone()));
})
});
#[cfg(feature = "rayon")]
- c.bench_function("roundtrip_filter_par 500k", |b| {
+ c.bench_function("500k filter_par", |b| {
b.iter(|| {
roundtrip_filter_par(black_box(cloud_points_500k.clone()));
})
});
- c.bench_function("roundtrip_filter 1.5m", |b| {
+ #[cfg(feature = "rayon")]
+ c.bench_function("500k filter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_filter_par_par(cloud_points_500k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("500k vec_filter", |b| {
+ b.iter(|| {
+ roundtrip_filter_vec(black_box(cloud_points_500k.clone()));
+ })
+ });
+
+ // Heavy computing
+ c.bench_function("500k iter_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing(black_box(cloud_points_500k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("500k iter_compute_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par(black_box(cloud_points_500k.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("500k iter_compute_par_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par_par(black_box(cloud_points_500k.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("500k vec_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing_vec(black_box(cloud_points_500k.clone()));
+ })
+ });
+
+ // 1.5m points (scale of small localmaps in SLAM)
+
+ // Moving memory
+ c.bench_function("1.5m iter", |b| {
+ b.iter(|| {
+ black_box(roundtrip(cloud_points_1_5m.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("1.5m iter_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par(cloud_points_1_5m.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("1.5m iter_par_par", |b| {
+ b.iter(|| {
+ black_box(roundtrip_par_par(cloud_points_1_5m.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("1.5m vec", |b| {
+ b.iter(|| {
+ black_box(roundtrip_vec(cloud_points_1_5m.clone()));
+ })
+ });
+
+ // Simple distance filter
+ c.bench_function("1.5m iter_filter", |b| {
b.iter(|| {
roundtrip_filter(black_box(cloud_points_1_5m.clone()));
})
});
#[cfg(feature = "rayon")]
- c.bench_function("roundtrip_filter_par 1.5m", |b| {
+ c.bench_function("1.5m iter_par_filter", |b| {
b.iter(|| {
black_box(roundtrip_filter_par(cloud_points_1_5m.clone()));
})
});
+ #[cfg(feature = "rayon")]
+ c.bench_function("1.5m iter_par_par_filter", |b| {
+ b.iter(|| {
+ black_box(roundtrip_filter_par_par(cloud_points_1_5m.clone()));
+ })
+ });
+
#[cfg(feature = "derive")]
- c.bench_function("roundtrip_filter_vec 1.5m", |b| {
+ c.bench_function("1.5m vec_filter", |b| {
b.iter(|| {
roundtrip_filter_vec(black_box(cloud_points_1_5m.clone()));
})
});
+
+ // Heavy computing
+ c.bench_function("1.5m iter_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing(black_box(cloud_points_1_5m.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("1.5m iter_compute_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par(black_box(cloud_points_1_5m.clone()));
+ })
+ });
+
+ #[cfg(feature = "rayon")]
+ c.bench_function("1.5m iter_compute_par_par", |b| {
+ b.iter(|| {
+ roundtrip_computing_par_par(black_box(cloud_points_1_5m.clone()));
+ })
+ });
+
+ #[cfg(feature = "derive")]
+ c.bench_function("1.5m vec_compute", |b| {
+ b.iter(|| {
+ roundtrip_computing_vec(black_box(cloud_points_1_5m.clone()));
+ })
+ });
}
criterion_group!(benches, roundtrip_benchmark);
diff --git a/examples/custom_enum_field_filter.rs b/examples/custom_enum_field_filter.rs
index 264422b..c86e50c 100644
--- a/examples/custom_enum_field_filter.rs
+++ b/examples/custom_enum_field_filter.rs
@@ -17,7 +17,8 @@ enum Label {
Car,
}
-// Define a custom point with an enum (not supported by PointCloud2)
+// Define a custom point with an enum.
+// This is normally not supported by PointCloud2 but we will explain the library how to handle it.
#[derive(Debug, PartialEq, Clone, Default)]
struct CustomPoint {
x: f32,
@@ -27,7 +28,7 @@ struct CustomPoint {
my_custom_label: Label,
}
-// For our convenience
+// Some convenience functions to convert between the enum and u8.
impl From