So your awesome mobile game seems to be doing pretty well,
but users are complaining about load time.
After some profiling, the problem soon becomes clear.
You're spending too much time deserializing your data.
My name is Colt McAnlis, and we can make your data loading
experience faster for users and easier for you
with the new flatbuffers library.
As you already know, loading your content
is a really gnarly process.
All of the data that comes from your content creation tools
like physics, animations, spreadsheet data,
have to all be stored in some sort of format
that you can load into your game and ship to customers.
And this is even counting the temporal stuff,
like sending your game data across a network connection
or saving your game to be reloaded later.
Since this process is so critical to game development,
how do we go about optimizing it for performance?
To do that, let's go back to the basics.
Serialization is the process of taking some in-memory data
structure and converting it into a data format which, one, can
be converted back to the in-memory structure
at some point in the future and, two, be somewhat
compact in order to not take up too much space.
Now, some of the more popular serialized formats out there
are XML and JSON, mainly because they are human readable.
That is, you can actually open these files into a text editor,
poke around, make changes, and actually understand
what you're doing.
And this popularity is further extended with native support
in languages like C#, Java, and JavaScript.
But in truth, these formats come with some serious drawbacks.
Firstly, they tend to be bloated.
The fact that these formats are human readable
means there's lots of overly verbose syntax
that's added to the format for the ease of readability
and use, making the file larger than it actually needs to be.
Secondly, the overly inflexible nature of these formats
puts an enormous strain on the deserialization process.
The parsing system has to read in string data
and then run analysis on it in order
to determine what data type it is before converting it
to that actual type in memory.
And this gets worse when your format supports
more advanced types like GUIDs, timestamps, and date objects.
The result is a deserialization process that's anything
but fast once complexity hits a certain level.
To address these problems, we've released a new open source
tool for games called flatbuffers.
This library prides itself going back to the basics
for serialization, that is, being fast for encoding
and decoding while also producing the smallest
encoded file possible.
Now, at a high level, flatbuffers
work by creating a file that describes the data types to be
serialized, called a schema, and then this
is handed over to a syntax compiler that
produces code files that you can include in your application
to encode and decode from the formats that you've defined.
Since your in-game structures tend to be complex,
the schema format that you feed into the compiler
allows you to describe your data structures
using type primitive relations, for example, objects reusable
classes, enums, and very basic types.
This layout allows flatbuffers to be type safe,
and further allows you to read from the serialized data format
without having to do any type conversions, memory
allocations, or unpacking during load time, which
is a huge speed boost.
Once you've created your schema files
for all your serializable data, you
feed those schema files into the flat C compiler
to generate source code files for your game.
With the right command line switches,
you can either generates C++, Java,
or even Go code files that you can drop right into your repo
and compile against.
Now, regardless of what language you're actually programming in,
using flatbuffers to load data is pretty simplistic.
Given your serialized stream of bytes,
pass it off to a single line of code
to convert it into your desired object,
and then you're ready to start using it.
Now, that's all fine and dandy, but how fast is it?
Let's take a look at how flatbuffers compare
to a few other options, namely protocol buffers and JSON.
We can see that with respect to both decode and encode times,
flatbuffers outperform the other formats
by a significant factor.
In fact, when stacked up side by side,
you can't see the flatbuffers time on the graph.
Hmm.
Now, just as important is the encoded size of the test data.
You can see that within extremely fast encode
and decode times flatbuffers are minimal when
it comes to both the original size of data
as well as the zlib compressed versions.
Oh, and one more thing.
You know how when you change the data formats of your game
and it creates a massive chaos vortex
with older formats, live builds, and compatibility?
Flatbuffers don't have that problem,
as they provide functionality to evolve your schemas
without affecting compatibility in older data and older
programs, which is pretty cool in my opinion.
Of course, there's tons of great other features
in the projects left to explore.
To learn more about the flatbuffers library,
or if you want more info on what's going on under the hood,
check out the flatbuffers Docs page
and then hop on over to grab the code at our github repo.
Serializing your data shouldn't be a pain.
Now go out there and build better games.
Better games-- did we write that to rhyme?