Skip to content

Commit 5147e01

Browse files
jmachowinskiJanosch Machowinski
andauthored
Performance improvements in serialization (#553)
* perf: Fixed high CPU usage due to dynamic_cast The dynamic_cast here turned out to be quite costly. Replacing it by the variant like function, we see a ~10% cpu usage reduction in our use case. Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com> * perf: Replaced virtual functions by templates This gives another performance improvement of around 2% of cpu usage in our usage scenario. Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com> --------- Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com> Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
1 parent b4963be commit 5147e01

2 files changed

Lines changed: 41 additions & 66 deletions

File tree

rmw_cyclonedds_cpp/src/Serialization.cpp

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -33,89 +33,73 @@
3333

3434
namespace rmw_cyclonedds_cpp
3535
{
36-
37-
struct CDRCursor
36+
template<typename Derived>
37+
struct CDRCursorBase
3838
{
39-
CDRCursor() = default;
40-
~CDRCursor() = default;
41-
42-
// don't want to accidentally copy
43-
explicit CDRCursor(CDRCursor const &) = delete;
44-
void operator=(CDRCursor const & x) = delete;
45-
46-
// virtual functions to be implemented
47-
// get the cursor's current offset.
48-
virtual size_t offset() const = 0;
49-
// advance the cursor.
50-
virtual void advance(size_t n_bytes) = 0;
51-
// Copy bytes to the current cursor location (if needed) and advance the cursor
52-
virtual void put_bytes(const void * data, size_t size) = 0;
53-
virtual bool ignores_data() const = 0;
54-
// Move the logical origin this many places
55-
virtual void rebase(ptrdiff_t relative_origin) = 0;
56-
5739
void align(size_t n_bytes)
5840
{
5941
assert(n_bytes > 0);
60-
size_t start_offset = offset();
42+
size_t start_offset = static_cast<Derived *>(this)->offset();
6143
if (n_bytes == 1 || start_offset % n_bytes == 0) {
6244
return;
6345
}
64-
advance(n_bytes - start_offset % n_bytes);
65-
assert(offset() - start_offset < n_bytes);
66-
assert(offset() % n_bytes == 0);
46+
static_cast<Derived *>(this)->advance(n_bytes - start_offset % n_bytes);
47+
assert(static_cast<Derived *>(this)->offset() - start_offset < n_bytes);
48+
assert(static_cast<Derived *>(this)->offset() % n_bytes == 0);
6749
}
68-
ptrdiff_t operator-(const CDRCursor & other) const
50+
51+
ptrdiff_t operator-(const CDRCursorBase & other) const
6952
{
70-
return static_cast<ptrdiff_t>(offset()) - static_cast<ptrdiff_t>(other.offset());
53+
return static_cast<ptrdiff_t>(static_cast<Derived *>(this)->offset()) -
54+
static_cast<ptrdiff_t>(static_cast<Derived &>(other).offset());
7155
}
7256
};
7357

74-
struct SizeCursor : public CDRCursor
58+
struct SizeCursor final : public CDRCursorBase<SizeCursor>
7559
{
7660
SizeCursor()
7761
: SizeCursor(0) {}
7862
explicit SizeCursor(size_t initial_offset)
7963
: m_offset(initial_offset) {}
80-
explicit SizeCursor(CDRCursor & c)
64+
explicit SizeCursor(SizeCursor & c)
8165
: m_offset(c.offset()) {}
8266

8367
size_t m_offset;
84-
size_t offset() const final {return m_offset;}
85-
void advance(size_t n_bytes) final {m_offset += n_bytes;}
86-
void put_bytes(const void *, size_t n_bytes) final {advance(n_bytes);}
87-
bool ignores_data() const final {return true;}
88-
void rebase(ptrdiff_t relative_origin) override
68+
size_t offset() const {return m_offset;}
69+
void advance(size_t n_bytes) {m_offset += n_bytes;}
70+
void put_bytes(const void *, size_t n_bytes) {advance(n_bytes);}
71+
bool ignores_data() const {return true;}
72+
void rebase(ptrdiff_t relative_origin)
8973
{
9074
// we're moving the *origin* so this has to change in the *opposite* direction
9175
m_offset -= relative_origin;
9276
}
9377
};
9478

95-
struct DataCursor : public CDRCursor
79+
struct DataCursor final : public CDRCursorBase<DataCursor>
9680
{
9781
const void * origin;
9882
void * position;
9983

10084
explicit DataCursor(void * position)
10185
: origin(position), position(position) {}
10286

103-
size_t offset() const final {return (const byte *)position - (const byte *)origin;}
104-
void advance(size_t n_bytes) final
87+
size_t offset() const {return (const byte *)position - (const byte *)origin;}
88+
void advance(size_t n_bytes)
10589
{
10690
std::memset(position, '\0', n_bytes);
10791
position = byte_offset(position, n_bytes);
10892
}
109-
void put_bytes(const void * bytes, size_t n_bytes) final
93+
void put_bytes(const void * bytes, size_t n_bytes)
11094
{
11195
if (n_bytes == 0) {
11296
return;
11397
}
11498
std::memcpy(position, bytes, n_bytes);
11599
position = byte_offset(position, n_bytes);
116100
}
117-
bool ignores_data() const final {return false;}
118-
void rebase(ptrdiff_t relative_origin) final {origin = byte_offset(origin, relative_origin);}
101+
bool ignores_data() const {return false;}
102+
void rebase(ptrdiff_t relative_origin) {origin = byte_offset(origin, relative_origin);}
119103
};
120104

121105
enum class EncodingVersion
@@ -236,6 +220,7 @@ class CDRWriter : public BaseCDRWriter
236220
serialize_top_level(&cursor, request);
237221
}
238222

223+
template<typename CDRCursor>
239224
void serialize_top_level(
240225
CDRCursor * cursor, const void * data) const
241226
{
@@ -257,6 +242,7 @@ class CDRWriter : public BaseCDRWriter
257242
}
258243
}
259244

245+
template<typename CDRCursor>
260246
void serialize_top_level(
261247
CDRCursor * cursor, const cdds_request_wrapper_t & request) const
262248
{
@@ -275,6 +261,7 @@ class CDRWriter : public BaseCDRWriter
275261
}
276262

277263
protected:
264+
template<typename CDRCursor>
278265
void put_rtps_header(CDRCursor * cursor) const
279266
{
280267
// beginning of message
@@ -297,6 +284,7 @@ class CDRWriter : public BaseCDRWriter
297284
cursor->put_bytes(rtps_header.data(), rtps_header.size());
298285
}
299286

287+
template<typename CDRCursor>
300288
void serialize_u32(CDRCursor * cursor, size_t value) const
301289
{
302290
assert(value <= std::numeric_limits<uint32_t>::max());
@@ -429,6 +417,7 @@ class CDRWriter : public BaseCDRWriter
429417
return sizeof_ < max_align ? sizeof_ : max_align;
430418
}
431419

420+
template<typename CDRCursor>
432421
void serialize(CDRCursor * cursor, const void * data, const PrimitiveValueType & value_type) const
433422
{
434423
cursor->align(get_cdr_alignof_primitive(value_type.type_kind()));
@@ -470,6 +459,7 @@ class CDRWriter : public BaseCDRWriter
470459
}
471460
}
472461

462+
template<typename CDRCursor>
473463
void serialize(CDRCursor * cursor, const void * data, const U8StringValueType & value_type) const
474464
{
475465
auto str = value_type.data(data);
@@ -479,6 +469,7 @@ class CDRWriter : public BaseCDRWriter
479469
cursor->put_bytes(&terminator, 1);
480470
}
481471

472+
template<typename CDRCursor>
482473
void serialize(CDRCursor * cursor, const void * data, const U16StringValueType & value_type) const
483474
{
484475
auto str = value_type.data(data);
@@ -497,12 +488,14 @@ class CDRWriter : public BaseCDRWriter
497488
}
498489
}
499490

491+
template<typename CDRCursor>
500492
void serialize(CDRCursor * cursor, const void * data, const ArrayValueType & value_type) const
501493
{
502494
serialize_many(
503495
cursor, value_type.get_data(data), value_type.array_size(), value_type.element_value_type());
504496
}
505497

498+
template<typename CDRCursor>
506499
void serialize(
507500
CDRCursor * cursor, const void * data,
508501
const SpanSequenceValueType & value_type) const
@@ -513,6 +506,7 @@ class CDRWriter : public BaseCDRWriter
513506
cursor, value_type.sequence_contents(data), count, value_type.element_value_type());
514507
}
515508

509+
template<typename CDRCursor>
516510
void serialize(
517511
CDRCursor * cursor, const void * data,
518512
const BoolVectorValueType & value_type) const
@@ -529,37 +523,17 @@ class CDRWriter : public BaseCDRWriter
529523
}
530524
}
531525

526+
template<typename CDRCursor>
532527
void serialize(CDRCursor * cursor, const void * data, const AnyValueType * value_type) const
533528
{
534529
if (lookup_trivially_serialized(cursor->offset(), value_type)) {
535530
cursor->put_bytes(data, value_type->sizeof_type());
536531
} else {
537-
// value_type->apply([&](const auto & vt) {return serialize(cursor, data, vt);});
538-
if (auto s = dynamic_cast<const PrimitiveValueType *>(value_type)) {
539-
return serialize(cursor, data, *s);
540-
}
541-
if (auto s = dynamic_cast<const U8StringValueType *>(value_type)) {
542-
return serialize(cursor, data, *s);
543-
}
544-
if (auto s = dynamic_cast<const U16StringValueType *>(value_type)) {
545-
return serialize(cursor, data, *s);
546-
}
547-
if (auto s = dynamic_cast<const StructValueType *>(value_type)) {
548-
return serialize(cursor, data, *s);
549-
}
550-
if (auto s = dynamic_cast<const ArrayValueType *>(value_type)) {
551-
return serialize(cursor, data, *s);
552-
}
553-
if (auto s = dynamic_cast<const SpanSequenceValueType *>(value_type)) {
554-
return serialize(cursor, data, *s);
555-
}
556-
if (auto s = dynamic_cast<const BoolVectorValueType *>(value_type)) {
557-
return serialize(cursor, data, *s);
558-
}
559-
unreachable();
532+
value_type->apply([&](const auto & vt) {return serialize(cursor, data, vt);});
560533
}
561534
}
562535

536+
template<typename CDRCursor>
563537
void serialize_many(
564538
CDRCursor * cursor, const void * data, size_t count,
565539
const AnyValueType * vt) const
@@ -594,6 +568,7 @@ class CDRWriter : public BaseCDRWriter
594568
}
595569
}
596570

571+
template<typename CDRCursor>
597572
void serialize(
598573
CDRCursor * cursor, const void * struct_data,
599574
const StructValueType & struct_info) const

rmw_cyclonedds_cpp/src/TypeSupport2.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ class U16StringValueType : public AnyValueType
391391
EValueType e_value_type() const final {return EValueType::U16StringValueType;}
392392
};
393393

394-
struct ROSIDLC_StringValueType : public U8StringValueType
394+
struct ROSIDLC_StringValueType final : public U8StringValueType
395395
{
396396
public:
397397
using type = rosidl_runtime_c__String;
@@ -413,7 +413,7 @@ struct ROSIDLC_StringValueType : public U8StringValueType
413413
size_t sizeof_type() const override {return sizeof(type);}
414414
};
415415

416-
class ROSIDLC_WStringValueType : public U16StringValueType
416+
class ROSIDLC_WStringValueType final : public U16StringValueType
417417
{
418418
public:
419419
using type = rosidl_runtime_c__U16String;
@@ -431,7 +431,7 @@ class ROSIDLC_WStringValueType : public U16StringValueType
431431
size_t sizeof_type() const override {return sizeof(type);}
432432
};
433433

434-
class ROSIDLCPP_StringValueType : public U8StringValueType
434+
class ROSIDLCPP_StringValueType final : public U8StringValueType
435435
{
436436
public:
437437
using type = std::string;
@@ -449,7 +449,7 @@ class ROSIDLCPP_StringValueType : public U8StringValueType
449449
size_t sizeof_type() const override {return sizeof(type);}
450450
};
451451

452-
class ROSIDLCPP_U16StringValueType : public U16StringValueType
452+
class ROSIDLCPP_U16StringValueType final : public U16StringValueType
453453
{
454454
public:
455455
using type = std::u16string;

0 commit comments

Comments
 (0)