Flatbuffer C++ UnpackTo optimization for vectors of non-bool bytes. (#6154)

UnpackTo copies vector elements one-by-one, which can be very inefficient depending on the quality of the compiler optimizations performed. This change updates the operation for vectors of bytes that aren't enums to use 'std::copy', which is usually highly optimized.

vectors of types that are more than one byte can't be optimized in this way because of the endianness of the serialized bytes vs. the target architecture endianness.

vectors of enums can't be optimized because they are required to be static_cast into the appropriate enum type when stored in the vector.

vectors of bools can be optimized in most cases, but since the standard
allows std::vector<bool> template specialization for space-savings,
std::copy doesn't work on every implementation (looking at you
Microsoft). Thus, this optimization is skipped for vector<bool>.

For a specific example, this improves the latency of unpacking large buffers on the Hexagon DSP by about 10x.

Co-authored-by: Matthew Markwell <markwell@google.com>
This commit is contained in:
mrmarkwell
2020-10-06 10:56:45 -07:00
committed by GitHub
parent 5975658ebd
commit 08943aa26f
4 changed files with 71 additions and 54 deletions

View File

@@ -2298,7 +2298,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = mana(); _o->mana = _e; }
{ auto _e = hp(); _o->hp = _e; }
{ auto _e = name(); if (_e) _o->name = _e->str(); }
{ auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } }
{ auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->inventory.begin()); } }
{ auto _e = color(); _o->color = _e; }
{ auto _e = test_type(); _o->test.type = _e; }
{ auto _e = test(); if (_e) _o->test.value = MyGame::Example::AnyUnion::UnPack(_e, test_type(), _resolver); }
@@ -2306,7 +2306,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } }
{ auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = std::unique_ptr<MyGame::Example::MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } }
{ auto _e = enemy(); if (_e) _o->enemy = std::unique_ptr<MyGame::Example::MonsterT>(_e->UnPack(_resolver)); }
{ auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer[_i] = _e->Get(_i); } } }
{ auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->testnestedflatbuffer.begin()); } }
{ auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<MyGame::Example::StatT>(_e->UnPack(_resolver)); }
{ auto _e = testbool(); _o->testbool = _e; }
{ auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; }
@@ -2324,7 +2324,7 @@ if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->testhashu32_fnv1a), s
{ auto _e = testf3(); _o->testf3 = _e; }
{ auto _e = testarrayofstring2(); if (_e) { _o->testarrayofstring2.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2[_i] = _e->Get(_i)->str(); } } }
{ auto _e = testarrayofsortedstruct(); if (_e) { _o->testarrayofsortedstruct.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofsortedstruct[_i] = *_e->Get(_i); } } }
{ auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->flex[_i] = _e->Get(_i); } } }
{ auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->flex.begin()); } }
{ auto _e = test5(); if (_e) { _o->test5.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test5[_i] = *_e->Get(_i); } } }
{ auto _e = vector_of_longs(); if (_e) { _o->vector_of_longs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_longs[_i] = _e->Get(_i); } } }
{ auto _e = vector_of_doubles(); if (_e) { _o->vector_of_doubles.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_doubles[_i] = _e->Get(_i); } } }
@@ -2478,7 +2478,7 @@ inline void TypeAliases::UnPackTo(TypeAliasesT *_o, const flatbuffers::resolver_
{ auto _e = u64(); _o->u64 = _e; }
{ auto _e = f32(); _o->f32 = _e; }
{ auto _e = f64(); _o->f64 = _e; }
{ auto _e = v8(); if (_e) { _o->v8.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->v8[_i] = _e->Get(_i); } } }
{ auto _e = v8(); if (_e) { _o->v8.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->v8.begin()); } }
{ auto _e = vf64(); if (_e) { _o->vf64.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vf64[_i] = _e->Get(_i); } } }
}