<story><title>FlatBuffers: a memory efficient serialization library</title><url>http://google-opensource.blogspot.com/2014/06/flatbuffers-memory-efficient.html</url></story><parent_chain><item><author>kentonv</author><text>Huh. So Google is releasing a competitor to Cap&amp;#x27;n Proto. As the former maintainer of Protobufs (at Google) and author of Cap&amp;#x27;n Proto (after Google), I&amp;#x27;m pretty surprised that I hadn&amp;#x27;t heard about this. I also don&amp;#x27;t recognize any of the names, so this is not from the people who were working on Protobufs at the time I left.&lt;p&gt;I&amp;#x27;m the main competitor, so take me with a grain of salt here.&lt;p&gt;The docs don&amp;#x27;t look very detailed, but taking a quick look through...&lt;p&gt;&amp;gt; &amp;quot;On purpose, the format leaves a lot of details about where exactly things live in memory undefined, e.g. fields in a table can have any order... To be able to access fields regardless of these uncertainties, we go through a vtable of offsets. Vtables are shared between any objects that happen to have the same vtable values.&amp;quot;&lt;p&gt;Hrm, that sounds like a lot of complexity and a big performance hit. In order to read a field from a struct, you have to do a vtable lookup to find the offset? Maybe you can still get that done in an inline accessor, but it will make the optimizer sad.&lt;p&gt;How is de-duping of vtables accomplished? It doesn&amp;#x27;t look like the API exposes any details about vtables, meaning you&amp;#x27;d have to do it magically behind the scenes, which seems expensive?&lt;p&gt;It looks like the authors may have been trying to maintain the concept of &amp;quot;optional fields&amp;quot; from Protobufs, where if you don&amp;#x27;t set an optional field, it takes zero bytes on the wire. But the main use of optional fields in practice is to implement unions -- i.e. a list of fields where only one should be filled in at a time.&lt;p&gt;Cap&amp;#x27;n Proto&amp;#x27;s solution to this was just to build unions into the language, something Protobufs should have done a long time ago.&lt;p&gt;&amp;gt; &amp;quot;FlatBuffers relies on new field declarations being added at the end, and earlier declarations to not be removed, but be marked deprecated when needed. We think this is an improvement over the manual number assignment that happens in Protocol Buffers.&amp;quot;&lt;p&gt;That&amp;#x27;s not an improvement at all. Declarations should be ordered semantically, so that related things go together. More importantly, even if you say that they can&amp;#x27;t be, developers will still do it, and will accidentally introduce incompatibilities. To make matters worse, it tends to be hard to detect these issues in testing, because your tests are probably build from the latest code. Simply adding field numbers as in Protobufs and Cap&amp;#x27;n Proto has proven an effective solution to this in practice.&lt;p&gt;Very surprised to see Google get this wrong, since they have more experience with this than anyone.&lt;p&gt;&amp;gt; Benchmarks&lt;p&gt;I couldn&amp;#x27;t find the benchmark code in the github repo, so it&amp;#x27;s hard to say what they may be measuring here. FlatBuffers presumably shares Cap&amp;#x27;n Proto&amp;#x27;s property that encodes and decodes take zero time, which makes it hard to create a meaningful benchmark in the first place. Indeed the numbers they put up kind of look like they&amp;#x27;re timing a noop loop. I can&amp;#x27;t see how the &amp;quot;traverse&amp;quot; time could be so much better than with protobufs, which makes me think the code might be written in such a way that the compiler was able to optimize away all the traverse time for FlatBuffers because it thought the results were unused anyway -- a mistake that&amp;#x27;s easy to make.&lt;p&gt;But I&amp;#x27;d love to see the code to verify. Hopefully I just missed it when digging through the repo.</text></item></parent_chain><comment><author>Aardappel</author><text>Hi. I designed most of FlatBuffers, so let me see if I can clarify:&lt;p&gt;Clearly, FlatBuffers seeks a different design tradeoff than Cap&amp;#x27;n Proto. We wanted to retain all the flexibility of Protobufs, while having the advantages of the &amp;quot;zero parsing &amp;#x2F; zero allocation&amp;quot; approach. That brought us to the vtable design.&lt;p&gt;In use cases where performance matters, i.e. you are churning through a large amount of data, you will be accessing the same vtable repeatedly, and the cost of the extra indirection (and the code associated with it) will be masked by the memory latency of the main data you&amp;#x27;re going through. It will be (close to) &amp;quot;for free&amp;quot;. Even in cases where that isn&amp;#x27;t the case, whether or not it is able to match Cap&amp;#x27;n Proto&amp;#x27;s accessor code is less interesting than it being endlessly faster than Protobuf and most other serializers out there, given that it is just as flexible.&lt;p&gt;vtables are de-duped on the fly during construction. It is typically not expensive.&lt;p&gt;Note this tiny overhead holds for &amp;quot;tables&amp;quot;, we also have naked &amp;quot;structs&amp;quot;, which do not have the indirection overhead, but have no forwards&amp;#x2F;backwards compatability. Useful for things like 2d&amp;#x2F;3d vector types, colors, and other small POD types that are used a lot.&lt;p&gt;FlatBuffers also has unions, which you should use instead of optionals when appropriate. We feel optionals have a lot of uses beyond just mere unions and forwards&amp;#x2F;backwards compatibility, however. Game objects can have a LOT of fields, many of which are often at their default value, and thus not stored on the wire. This gives significant compression. The zero-byte compression in Cap&amp;#x27;n Proto is cool, but we prefer to not have to use additional buffers when reading. Optionals also give a lot of design freedom, i.e. you can add a field that you know is only needed for very few instances without fear of bloating your binaries, as an alternative to &amp;quot;subclassing&amp;quot;, or indeed unions.&lt;p&gt;On field declaration order: to each his own, I guess. That said, the omission of explicit field id&amp;#x27;s is something that&amp;#x27;s handled at the level of the schema compiler, we could easily allow optional id declarations in the schema for people who want the flexibility of declaring things in an arbitrary order. Noted.&lt;p&gt;We should clean up the benchmark code, so it can be included, yes. It is not running a noop loop, we made sure of that. I haven&amp;#x27;t verified what makes Protobuf traversal that much slower, I am guessing it&amp;#x27;s causing a memory allocation somewhere.</text></comment>
<story><title>FlatBuffers: a memory efficient serialization library</title><url>http://google-opensource.blogspot.com/2014/06/flatbuffers-memory-efficient.html</url></story><parent_chain><item><author>kentonv</author><text>Huh. So Google is releasing a competitor to Cap&amp;#x27;n Proto. As the former maintainer of Protobufs (at Google) and author of Cap&amp;#x27;n Proto (after Google), I&amp;#x27;m pretty surprised that I hadn&amp;#x27;t heard about this. I also don&amp;#x27;t recognize any of the names, so this is not from the people who were working on Protobufs at the time I left.&lt;p&gt;I&amp;#x27;m the main competitor, so take me with a grain of salt here.&lt;p&gt;The docs don&amp;#x27;t look very detailed, but taking a quick look through...&lt;p&gt;&amp;gt; &amp;quot;On purpose, the format leaves a lot of details about where exactly things live in memory undefined, e.g. fields in a table can have any order... To be able to access fields regardless of these uncertainties, we go through a vtable of offsets. Vtables are shared between any objects that happen to have the same vtable values.&amp;quot;&lt;p&gt;Hrm, that sounds like a lot of complexity and a big performance hit. In order to read a field from a struct, you have to do a vtable lookup to find the offset? Maybe you can still get that done in an inline accessor, but it will make the optimizer sad.&lt;p&gt;How is de-duping of vtables accomplished? It doesn&amp;#x27;t look like the API exposes any details about vtables, meaning you&amp;#x27;d have to do it magically behind the scenes, which seems expensive?&lt;p&gt;It looks like the authors may have been trying to maintain the concept of &amp;quot;optional fields&amp;quot; from Protobufs, where if you don&amp;#x27;t set an optional field, it takes zero bytes on the wire. But the main use of optional fields in practice is to implement unions -- i.e. a list of fields where only one should be filled in at a time.&lt;p&gt;Cap&amp;#x27;n Proto&amp;#x27;s solution to this was just to build unions into the language, something Protobufs should have done a long time ago.&lt;p&gt;&amp;gt; &amp;quot;FlatBuffers relies on new field declarations being added at the end, and earlier declarations to not be removed, but be marked deprecated when needed. We think this is an improvement over the manual number assignment that happens in Protocol Buffers.&amp;quot;&lt;p&gt;That&amp;#x27;s not an improvement at all. Declarations should be ordered semantically, so that related things go together. More importantly, even if you say that they can&amp;#x27;t be, developers will still do it, and will accidentally introduce incompatibilities. To make matters worse, it tends to be hard to detect these issues in testing, because your tests are probably build from the latest code. Simply adding field numbers as in Protobufs and Cap&amp;#x27;n Proto has proven an effective solution to this in practice.&lt;p&gt;Very surprised to see Google get this wrong, since they have more experience with this than anyone.&lt;p&gt;&amp;gt; Benchmarks&lt;p&gt;I couldn&amp;#x27;t find the benchmark code in the github repo, so it&amp;#x27;s hard to say what they may be measuring here. FlatBuffers presumably shares Cap&amp;#x27;n Proto&amp;#x27;s property that encodes and decodes take zero time, which makes it hard to create a meaningful benchmark in the first place. Indeed the numbers they put up kind of look like they&amp;#x27;re timing a noop loop. I can&amp;#x27;t see how the &amp;quot;traverse&amp;quot; time could be so much better than with protobufs, which makes me think the code might be written in such a way that the compiler was able to optimize away all the traverse time for FlatBuffers because it thought the results were unused anyway -- a mistake that&amp;#x27;s easy to make.&lt;p&gt;But I&amp;#x27;d love to see the code to verify. Hopefully I just missed it when digging through the repo.</text></item></parent_chain><comment><author>tlrobinson</author><text>Incidentally, the first time I saw the Cap&amp;#x27;n Proto homepage I thought the whole thing was a joke because I saw the &amp;quot;cerealization protocol&amp;quot; tagline and &amp;quot;infinitely faster&amp;quot; badge and stopped reading after the first paragraph...&lt;p&gt;EDIT: Oh yeah, and when I skimmed the rest of the page this &amp;quot;confirmed&amp;quot; my suspicions: &lt;i&gt;&amp;quot;Time-traveling RPC: Cap’n Proto features an RPC system implements time travel such that call results are returned to the client before the request even arrives at the server!&amp;quot;&lt;/i&gt;. I&amp;#x27;m familiar with promise pipelining but that sentence (and diagram) made it sound like a complete joke.</text></comment>