Reduce memory usage of the static flatbuffer API
This contains a couple of changes, which work together and are a bit
hard to separate out.
1) Instead of requiring the whole contents of a sub-message or vector to
be aligned, split the alignment requirement up into an alignment
requirement at an offset into the message. This lets us leave the
length field in a message, for example, at 4 byte alignment when the
body requires 8 byte alignment. This enables better packing of
fields.
2) From James, don't pre-reserve space for vectors with 0 length. They
will trigger a re-allocation anyways when they are used since there
is no space allocated, so pre-allocating doesn't help.
3) Remove padding at the end of messages and require the allocator to
handle it instead. We used to allocate kSize + kAlign and then
manually align things, which resulted in wasted space.
4) Automatically add any extra padding after a vector to the vector.
For some small vectors, this lets us use the padding for the vector
rather than allocating more space.
5) Shrink the code generated for the object offsets by adding constexpr
variables with the previous object size rather than inlining it.
This results in a much faster build since clang-format was fighting
the large fields at build time.
6) Sort fields in a flatbuffer by alignment to pack them better.
Change-Id: I5af440855e3425be31fa7f30c68af552fcf06cb2
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/flatbuffers/static_flatbuffers_test.cc b/aos/flatbuffers/static_flatbuffers_test.cc
index 0929d17..4a8b9e9 100644
--- a/aos/flatbuffers/static_flatbuffers_test.cc
+++ b/aos/flatbuffers/static_flatbuffers_test.cc
@@ -591,7 +591,12 @@
{
auto aligned_vector = object->mutable_vector_aligned();
ASSERT_TRUE(aligned_vector->reserve(100));
- EXPECT_EQ(100, aligned_vector->capacity());
+
+ VLOG(1) << AnnotateBinaries(test_schema_, builder.buffer());
+ // Since the allocator is going to allocate in blocks of 64, we end up
+ // with more capacity than we asked for. Better to have it than to leave
+ // it as unusable padding.
+ EXPECT_EQ(115, aligned_vector->capacity());
ASSERT_TRUE(builder.AsFlatbufferSpan().Verify())
<< aligned_vector->SerializationDebugString();
EXPECT_EQ(expected_contents,
@@ -657,11 +662,16 @@
{
auto unspecified_vector = object->add_unspecified_length_vector();
ASSERT_NE(nullptr, unspecified_vector);
- ASSERT_EQ(0, unspecified_vector->capacity());
+ ASSERT_EQ(60, unspecified_vector->capacity());
+ for (size_t i = 0; i < 60; ++i) {
+ ASSERT_TRUE(unspecified_vector->emplace_back(0));
+ }
ASSERT_FALSE(unspecified_vector->emplace_back(0));
- ASSERT_TRUE(unspecified_vector->reserve(2));
- ASSERT_TRUE(unspecified_vector->emplace_back(1));
- ASSERT_TRUE(unspecified_vector->emplace_back(2));
+ ASSERT_TRUE(unspecified_vector->reserve(64));
+ ASSERT_EQ(124, unspecified_vector->capacity());
+ for (size_t i = 0; i < 64; ++i) {
+ ASSERT_TRUE(unspecified_vector->emplace_back(1));
+ }
ASSERT_FALSE(unspecified_vector->emplace_back(3));
ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
}
@@ -927,10 +937,14 @@
{
auto vector = object->add_unspecified_length_vector();
// Confirm that the vector does indeed start out at zero length.
+ ASSERT_EQ(vector->capacity(), 60);
+ for (size_t i = 0; i < 60; ++i) {
+ ASSERT_TRUE(vector->emplace_back(i));
+ }
ASSERT_FALSE(vector->emplace_back(4));
ASSERT_TRUE(vector->reserve(9000));
vector->resize(256);
- for (size_t index = 0; index < 256; ++index) {
+ for (size_t index = 60; index < 256; ++index) {
vector->at(index) = static_cast<uint8_t>(index);
}
}