Skip to content

Commit 969664c

Browse files
authored
[wpiutil] Faster nanopb submessage encode (#7374)
Due to how submessages are encoded (with a length prefix), nanopb currently does the encoding twice. It encodes once to get the length to write, then writes the length, then reencodes the entire message a 2nd time. This results in a requirement that each encode always encodes the same. Generally, this is fine, but it'd be nice to not make this a requirement. The double encode also requires going through the entire set of fields again, which has the possibility to be slow. Instead of doing this, write to a temporary SmallVector. Then we can just encode the length of that buffer, and do a memcpy into primary stream. Theoretically in most cases, this should be much faster.
1 parent 1e545c3 commit 969664c

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,28 @@ bool detail::WriteFromStdVector(pb_ostream_t* stream, const pb_byte_t* buf,
4848
vec->insert(vec->end(), buf, buf + count);
4949
return true;
5050
}
51+
52+
bool detail::WriteSubmessage(pb_ostream_t* stream, const pb_msgdesc_t* desc,
53+
const void* msg) {
54+
// Write the submessage to a separate buffer
55+
wpi::SmallVector<uint8_t, 64> buf;
56+
pb_ostream_t subStream{
57+
.callback = WriteFromSmallVector,
58+
.state = &buf,
59+
.max_size = SIZE_MAX,
60+
.bytes_written = 0,
61+
.errmsg = nullptr,
62+
};
63+
if (!pb_encode(&subStream, desc, msg)) {
64+
return false;
65+
}
66+
67+
uint64_t size = static_cast<uint64_t>(buf.size());
68+
69+
// Write the size to the original stream.
70+
if (!pb_encode_varint(stream, size)) {
71+
return false;
72+
}
73+
74+
return pb_write(stream, reinterpret_cast<const pb_byte_t*>(buf.data()), size);
75+
}

wpiutil/src/main/native/include/wpi/protobuf/Protobuf.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ bool WriteFromSmallVector(pb_ostream_t* stream, const pb_byte_t* buf,
4343

4444
bool WriteFromStdVector(pb_ostream_t* stream, const pb_byte_t* buf,
4545
size_t count);
46+
47+
bool WriteSubmessage(pb_ostream_t* stream, const pb_msgdesc_t* desc,
48+
const void* msg);
4649
} // namespace detail
4750

4851
/**
@@ -208,7 +211,8 @@ class ProtoOutputStream {
208211
bool Encode(
209212
const typename Protobuf<std::remove_cvref_t<T>>::MessageStruct& msg) {
210213
if (m_streamMsg) {
211-
return pb_encode_submessage(m_streamMsg, m_msgDesc, &msg);
214+
return detail::WriteSubmessage(m_streamMsg, m_msgDesc, &msg);
215+
// return pb_encode_submessage(m_streamMsg, m_msgDesc, &msg);
212216
}
213217
return pb_encode(&m_streamLocal, m_msgDesc, &msg);
214218
}

0 commit comments

Comments
 (0)