Build the mbuf directly instead of copying in web_proxy
No sense doing a malloc followed by a memcpy for each packet. Instead,
we know how big the message will be, so allocate that much memory and
build directly into it.
Change-Id: Ie2361ced5403ff481dd10b30e8d9f106071c506b
diff --git a/aos/network/web_proxy.cc b/aos/network/web_proxy.cc
index 6147e46..b53feab 100644
--- a/aos/network/web_proxy.cc
+++ b/aos/network/web_proxy.cc
@@ -199,17 +199,25 @@
<< "packets";
for (int packet_index = 0;
packet_index < GetPacketCount(fetcher_->context()); ++packet_index) {
- flatbuffers::FlatBufferBuilder fbb;
- flatbuffers::Offset<MessageHeader> message_offset =
- PackMessage(&fbb, fetcher_->context(), channel_index_, packet_index);
- fbb.Finish(message_offset);
+ // Pack directly into the mbuffer. This is admittedly a bit painful.
+ const size_t packet_size =
+ PackedMessageSize(fetcher_->context(), packet_index);
+ struct mbuf *mbuffer = mbuf_alloc(packet_size);
- const flatbuffers::DetachedBuffer buffer = fbb.Release();
+ {
+ // Wrap a pre-allocated builder around the mbuffer.
+ PreallocatedAllocator allocator(mbuf_buf(mbuffer), packet_size);
+ flatbuffers::FlatBufferBuilder fbb(packet_size, &allocator);
+ flatbuffers::Offset<MessageHeader> message_offset = PackMessage(
+ &fbb, fetcher_->context(), channel_index_, packet_index);
+ fbb.Finish(message_offset);
-
- struct mbuf *mbuffer = mbuf_alloc(buffer.size());
- mbuf_write_mem(mbuffer, buffer.data(), buffer.size());
- mbuf_set_pos(mbuffer, 0);
+ // Now, the flatbuffer is built from the back to the front. So any
+ // extra memory will be at the front. Setup the end and start pointers
+ // on the mbuf.
+ mbuf_set_end(mbuffer, packet_size);
+ mbuf_set_pos(mbuffer, packet_size - fbb.GetSize());
+ }
message.data.emplace_back(
std::shared_ptr<struct mbuf>(mbuffer, mem_deref));
diff --git a/aos/network/web_proxy_utils.cc b/aos/network/web_proxy_utils.cc
index deb4a38..d6148d4 100644
--- a/aos/network/web_proxy_utils.cc
+++ b/aos/network/web_proxy_utils.cc
@@ -9,6 +9,10 @@
// the middle which seems to work.
constexpr size_t kPacketSize = 125000;
+// Max header size we have seen is 72 bytes, followed by 48 bytes of scratch
+// space.
+constexpr size_t kMaxHeaderSize = 72 + 48;
+
int GetPacketCountFromSize(const int packet_size) {
return packet_size / kPacketSize + 1;
}
@@ -35,6 +39,19 @@
return GetPacketCountFromSize(context.size);
}
+size_t PackedMessageSize(const Context &context, int packet_index) {
+ // Make sure the final size is aligned because flatbuffers will align it up
+ // otherwise.
+ constexpr size_t kAlignment = 8;
+ if (kPacketSize * (packet_index + 1) < context.size) {
+ return (kPacketSize + kMaxHeaderSize + kAlignment - 1) & ~(kAlignment - 1);
+ } else {
+ const int prefix_size = kPacketSize * packet_index;
+ return (context.size - prefix_size + kMaxHeaderSize + kAlignment - 1) &
+ ~(kAlignment - 1);
+ }
+}
+
flatbuffers::Offset<MessageHeader> PackMessage(
flatbuffers::FlatBufferBuilder *fbb, const Context &context,
int channel_index, int packet_index) {
diff --git a/aos/network/web_proxy_utils.h b/aos/network/web_proxy_utils.h
index cfed19d..19b496d 100644
--- a/aos/network/web_proxy_utils.h
+++ b/aos/network/web_proxy_utils.h
@@ -14,6 +14,10 @@
flatbuffers::FlatBufferBuilder *fbb, const Context &context,
int channel_index, int packet_index);
+// Returns the size that the overall packed message packed by PackMessage will
+// be for the provided packet index.
+size_t PackedMessageSize(const Context &context, int packet_index);
+
// Packs the provided raw data into a series of MessageHeader's of the
// appropriate length.
std::vector<FlatbufferDetachedBuffer<MessageHeader>> PackBuffer(