Skip to content

Commit cebb972

Browse files
Don't copy contiguous bytes on reception (#343)
* Don't copy contiguous bytes on reception This uses the slices iterator API of zenoh-cpp to avoid unecessarily copying bytes into a vecotr, if and only if the bytes is made up of exactly one slice. * Don't use auto type specifiers * Remove unused `<vector>` includes * Explain lifetime of `Contiguous::slice` * Move `Payload` into `zenoh_utils` Signed-off-by: Mahmoud Mazouz <mazouz.mahmoud@outlook.com> Co-authored-by: Chris Lalancette <clalancette@gmail.com>
1 parent 57a6b4b commit cebb972

File tree

4 files changed

+86
-9
lines changed

4 files changed

+86
-9
lines changed

rmw_zenoh_cpp/src/detail/rmw_subscription_data.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <string>
2525
#include <utility>
2626
#include <variant>
27-
#include <vector>
2827

2928
#include "attachment_helpers.hpp"
3029
#include "cdr.hpp"
@@ -44,10 +43,10 @@ namespace rmw_zenoh_cpp
4443
{
4544
///=============================================================================
4645
SubscriptionData::Message::Message(
47-
std::vector<uint8_t> && p,
46+
const zenoh::Bytes & p,
4847
uint64_t recv_ts,
4948
AttachmentData && attachment_)
50-
: payload(std::move(p)), recv_timestamp(recv_ts), attachment(std::move(attachment_))
49+
: payload(p), recv_timestamp(recv_ts), attachment(std::move(attachment_))
5150
{
5251
}
5352

@@ -225,7 +224,7 @@ bool SubscriptionData::init()
225224

226225
sub_data->add_new_message(
227226
std::make_unique<SubscriptionData::Message>(
228-
sample.get_payload().as_vector(),
227+
sample.get_payload(),
229228
std::chrono::system_clock::now().time_since_epoch().count(),
230229
std::move(attachment_data)),
231230
std::string(sample.get_keyexpr().as_string_view()));
@@ -303,13 +302,12 @@ bool SubscriptionData::init()
303302
"Unable to obtain attachment")
304303
return;
305304
}
306-
auto payload = sample.get_payload().clone();
307305
auto attachment_value = attachment.value();
308306

309307
AttachmentData attachment_data(attachment_value);
310308
sub_data->add_new_message(
311309
std::make_unique<SubscriptionData::Message>(
312-
payload.as_vector(),
310+
sample.get_payload(),
313311
std::chrono::system_clock::now().time_since_epoch().count(),
314312
std::move(attachment_data)),
315313
std::string(sample.get_keyexpr().as_string_view()));

rmw_zenoh_cpp/src/detail/rmw_subscription_data.hpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include <string>
2626
#include <unordered_map>
2727
#include <variant>
28-
#include <vector>
2928

3029
#include <zenoh.hxx>
3130

@@ -51,13 +50,13 @@ class SubscriptionData final : public std::enable_shared_from_this<SubscriptionD
5150
struct Message
5251
{
5352
explicit Message(
54-
std::vector<uint8_t> && p,
53+
const zenoh::Bytes & bytes,
5554
uint64_t recv_ts,
5655
AttachmentData && attachment);
5756

5857
~Message();
5958

60-
std::vector<uint8_t> payload;
59+
Payload payload;
6160
uint64_t recv_timestamp;
6261
AttachmentData attachment;
6362
};

rmw_zenoh_cpp/src/detail/zenoh_utils.cpp

+51
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,55 @@ int64_t get_system_time_in_ns()
7777
return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
7878
}
7979

80+
///=============================================================================
81+
Payload::Payload(const zenoh::Bytes & bytes)
82+
{
83+
// NOTE(fuzzypixelz): `zenoh::Bytes` is an list of reference-couted buffers. When the list of
84+
// buffers contains exactly one element, it is not necessary to concatenate the list of buffers.
85+
// In this case, we store a clone of the bytes object to maintain a non-zero reference-count on
86+
// the buffer. This ensures that the slice into said buffer stays valid until we drop our copy
87+
// of the bytes object (at the very least). This case corresponds to the `Contiguous`
88+
// alternative of the `bytes_` variant and aims to optimize away a memcpy during "session-local"
89+
// communication.
90+
91+
zenoh::Bytes::SliceIterator slices = bytes.slice_iter();
92+
std::optional<zenoh::Slice> slice = slices.next();
93+
if (!slice.has_value()) {
94+
bytes_ = nullptr;
95+
} else {
96+
if (!slices.next().has_value()) {
97+
bytes_ = Contiguous {slice.value(), bytes.clone()};
98+
} else {
99+
bytes_ = bytes.as_vector();
100+
}
101+
}
102+
}
103+
104+
const uint8_t * Payload::data() const
105+
{
106+
if (std::holds_alternative<Empty>(bytes_)) {
107+
return nullptr;
108+
} else if (std::holds_alternative<NonContiguous>(bytes_)) {
109+
return std::get<NonContiguous>(bytes_).data();
110+
} else {
111+
return std::get<Contiguous>(bytes_).slice.data;
112+
}
113+
}
114+
115+
size_t Payload::size() const
116+
{
117+
if (std::holds_alternative<Empty>(bytes_)) {
118+
return 0;
119+
} else if (std::holds_alternative<NonContiguous>(bytes_)) {
120+
return std::get<NonContiguous>(bytes_).size();
121+
} else {
122+
return std::get<Contiguous>(bytes_).slice.len;
123+
}
124+
}
125+
126+
bool Payload::empty() const
127+
{
128+
return std::holds_alternative<Empty>(bytes_);
129+
}
130+
80131
} // namespace rmw_zenoh_cpp

rmw_zenoh_cpp/src/detail/zenoh_utils.hpp

+29
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include <chrono>
2222
#include <functional>
2323
#include <optional>
24+
#include <utility>
25+
#include <variant>
26+
#include <vector>
2427

2528
#include "rmw/types.h"
2629

@@ -63,6 +66,32 @@ class ZenohQuery final
6366
};
6467

6568
int64_t get_system_time_in_ns();
69+
70+
class Payload
71+
{
72+
public:
73+
explicit Payload(const zenoh::Bytes & bytes);
74+
75+
~Payload() = default;
76+
77+
const uint8_t * data() const;
78+
79+
size_t size() const;
80+
81+
bool empty() const;
82+
83+
private:
84+
struct Contiguous
85+
{
86+
zenoh::Slice slice;
87+
zenoh::Bytes bytes;
88+
};
89+
using NonContiguous = std::vector<uint8_t>;
90+
using Empty = std::nullptr_t;
91+
// Is `std::vector<uint8_t>` in case of a non-contiguous payload
92+
// and `zenoh::Slice` plus a `zenoh::Bytes` otherwise.
93+
std::variant<NonContiguous, Contiguous, Empty> bytes_;
94+
};
6695
} // namespace rmw_zenoh_cpp
6796

6897
#endif // DETAIL__ZENOH_UTILS_HPP_

0 commit comments

Comments
 (0)