Added Google benchmarks (and gtests) (#6920)

* Added Google benchmarks (and gtests)

* Default building benchmarks to OFF as it requires c++11

* Separate benchmark CMakeLists.txt to its own file

* Move output directory to target just flatbenchmark
This commit is contained in:
Derek Bailey 2021-11-15 13:41:22 -08:00 committed by GitHub
parent 927175ea20
commit 0989fc5e59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 676 additions and 0 deletions

4
.gitignore vendored
View File

@ -46,6 +46,8 @@ project.properties
proguard-project.txt
linklint_results
Makefile
flatbenchmark
flatbenchmark.exe
flatc
flatc.exe
flathash
@ -143,3 +145,5 @@ flatbuffers.pc
**/FlatBuffers.Test.Swift.xcodeproj
**/html/**
**/latex/**
# https://cmake.org/cmake/help/latest/module/FetchContent.html#variable:FETCHCONTENT_BASE_DIR
_deps/

View File

@ -16,6 +16,9 @@ option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler"
option(FLATBUFFERS_STATIC_FLATC "Build flatbuffers compiler with -static flag"
OFF)
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
option(FLATBUFFERS_BUILD_BENCHMARKS "Enable the build of flatbenchmark. \"
Requires C++11."
OFF)
option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
option(FLATBUFFERS_BUILD_SHAREDLIB
"Enable the build of the flatbuffers shared library"
@ -715,3 +718,8 @@ if(UNIX)
include(CPack)
endif()
endif()
# Include for running Google Benchmarks.
if(FLATBUFFERS_BUILD_BENCHMARKS AND CMAKE_VERSION VERSION_GREATER 3.13)
add_subdirectory(benchmarks)
endif()

81
benchmarks/CMakeLists.txt Normal file
View File

@ -0,0 +1,81 @@
# Setup for running Google Benchmarks (https://github.com/google/benchmark) on
# flatbuffers. This requires both that benchmark library and its depenency gtest
# to build. Instead of including them here or doing a submodule, this uses
# FetchContent (https://cmake.org/cmake/help/latest/module/FetchContent.html) to
# grab the dependencies at config time. This requires CMake 3.14 or higher.
cmake_minimum_required(VERSION 3.14)
include(FetchContent)
# No particular reason for the specific GIT_TAGs for the following repos, they
# were just the latest releases when this was added.
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release-1.11.0
)
FetchContent_Declare(
googlebenchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG f91b6b42b1b9854772a90ae9501464a161707d1e # v1.6.0
)
# For Windows: Prevent overriding the parent project's compiler/linker
# settings.
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(
googletest
googlebenchmark
)
set(CPP_BENCH_DIR cpp)
set(CPP_FB_BENCH_DIR ${CPP_BENCH_DIR}/flatbuffers)
set(CPP_BENCH_FBS ${CPP_FB_BENCH_DIR}/bench.fbs)
set(CPP_BENCH_FB_GEN ${CPP_FB_BENCH_DIR}/bench_generated.h)
set(FlatBenchmark_SRCS
${CPP_BENCH_DIR}/benchmark_main.cpp
${CPP_BENCH_DIR}/bench.h
${CPP_FB_BENCH_DIR}/fb_bench.cpp
${CPP_FB_BENCH_DIR}/fb_bench.h
${CPP_BENCH_FB_GEN}
)
# Generate the flatbuffers benchmark code from the flatbuffers schema using
# flatc itself, thus it depends on flatc. This also depends on the C++ runtime
# flatbuffers and the schema file itself, so it should auto-generated at the
# correct times.
add_custom_command(
OUTPUT ${CPP_BENCH_FB_GEN}
COMMAND
"${FLATBUFFERS_FLATC_EXECUTABLE}"
--cpp
-o ${CPP_FB_BENCH_DIR}
${CPP_BENCH_FBS}
DEPENDS
flatc
flatbuffers
${CPP_BENCH_FBS}
COMMENT "Run Flatbuffers Benchmark Codegen: ${CPP_BENCH_FB_GEN}"
VERBATIM)
# The main flatbuffers benchmark executable
add_executable(flatbenchmark ${FlatBenchmark_SRCS})
# Benchmark requires C++11
target_compile_features(flatbenchmark PUBLIC
cxx_std_11
)
# Set the output directory to the root binary directory
set_target_properties(flatbenchmark
PROPERTIES RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}"
)
# The includes of the benchmark files are fully qualified from flatbuffers root.
target_include_directories(flatbenchmark PUBLIC ${CMAKE_SOURCE_DIR})
target_link_libraries(flatbenchmark
benchmark::benchmark_main # _main to use their entry point
gtest # Link to gtest so we can also assert in the benchmarks
)

19
benchmarks/cpp/bench.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef BENCHMARKS_CPP_BENCH_H_
#define BENCHMARKS_CPP_BENCH_H_
#include <cstdint>
struct Bench {
virtual ~Bench() {}
inline void Add(int64_t value) { sum += value; }
virtual uint8_t *Encode(void *buf, int64_t &len) = 0;
virtual void *Decode(void *buf, int64_t len) = 0;
virtual int64_t Use(void *decoded) = 0;
virtual void Dealloc(void *decoded) = 0;
int64_t sum = 0;
};
#endif // BENCHMARKS_CPP_BENCH_H_

View File

@ -0,0 +1,61 @@
#include <benchmark/benchmark.h>
#include <gtest/gtest.h>
#include "benchmarks/cpp/bench.h"
#include "benchmarks/cpp/flatbuffers/fb_bench.h"
static void BM_Flatbuffers_Encode(benchmark::State &state) {
const int64_t kBufferLength = 1024;
uint8_t buffer[kBufferLength];
int64_t length;
StaticAllocator allocator(&buffer[0]);
std::unique_ptr<Bench> bench = NewFlatBuffersBench(kBufferLength, &allocator);
for (auto _ : state) {
bench->Encode(buffer, length);
benchmark::DoNotOptimize(length);
}
}
BENCHMARK(BM_Flatbuffers_Encode);
static void BM_Flatbuffers_Decode(benchmark::State &state) {
const int64_t kBufferLength = 1024;
uint8_t buffer[kBufferLength];
int64_t length;
StaticAllocator allocator(&buffer[0]);
std::unique_ptr<Bench> bench = NewFlatBuffersBench(kBufferLength, &allocator);
uint8_t* encoded = bench->Encode(buffer, length);
for (auto _ : state) {
void* decoded = bench->Decode(encoded, length);
benchmark::DoNotOptimize(decoded);
}
}
BENCHMARK(BM_Flatbuffers_Decode);
static void BM_Flatbuffers_Use(benchmark::State &state) {
const int64_t kBufferLength = 1024;
uint8_t buffer[kBufferLength];
int64_t length;
StaticAllocator allocator(&buffer[0]);
std::unique_ptr<Bench> bench = NewFlatBuffersBench(kBufferLength, &allocator);
uint8_t* encoded = bench->Encode(buffer, length);
void* decoded = bench->Decode(encoded, length);
int64_t sum = 0;
for (auto _ : state) {
sum = bench->Use(decoded);
}
EXPECT_EQ(sum , 218812692406581874);
}
BENCHMARK(BM_Flatbuffers_Use);

View File

@ -0,0 +1,52 @@
// Copyright 2021 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// trying to represent a typical mix of datatypes:
// 1 array of 3 elements, each element: 1 string, 3 nested objects, 9 scalars
// root element has the array, additional string and an enum
namespace benchmarks_flatbuffers;
enum Enum : short { Apples, Pears, Bananas}
struct Foo {
id:ulong;
count:short;
prefix:byte;
length:uint;
}
struct Bar {
parent:Foo;
time:int;
ratio:float;
size:ushort;
}
table FooBar {
sibling:Bar;
name:string;
rating:double;
postfix:ubyte;
}
table FooBarContainer {
list:[FooBar]; // 3 copies of the above
initialized:bool;
fruit:Enum;
location:string;
}
root_type FooBarContainer;

View File

@ -0,0 +1,347 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_
#define FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_
#include "flatbuffers/flatbuffers.h"
namespace benchmarks_flatbuffers {
struct Foo;
struct Bar;
struct FooBar;
struct FooBarBuilder;
struct FooBarContainer;
struct FooBarContainerBuilder;
enum Enum : int16_t {
Enum_Apples = 0,
Enum_Pears = 1,
Enum_Bananas = 2,
Enum_MIN = Enum_Apples,
Enum_MAX = Enum_Bananas
};
inline const Enum (&EnumValuesEnum())[3] {
static const Enum values[] = {
Enum_Apples,
Enum_Pears,
Enum_Bananas
};
return values;
}
inline const char * const *EnumNamesEnum() {
static const char * const names[4] = {
"Apples",
"Pears",
"Bananas",
nullptr
};
return names;
}
inline const char *EnumNameEnum(Enum e) {
if (flatbuffers::IsOutRange(e, Enum_Apples, Enum_Bananas)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesEnum()[index];
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Foo FLATBUFFERS_FINAL_CLASS {
private:
uint64_t id_;
int16_t count_;
int8_t prefix_;
int8_t padding0__;
uint32_t length_;
public:
Foo()
: id_(0),
count_(0),
prefix_(0),
padding0__(0),
length_(0) {
(void)padding0__;
}
Foo(uint64_t _id, int16_t _count, int8_t _prefix, uint32_t _length)
: id_(flatbuffers::EndianScalar(_id)),
count_(flatbuffers::EndianScalar(_count)),
prefix_(flatbuffers::EndianScalar(_prefix)),
padding0__(0),
length_(flatbuffers::EndianScalar(_length)) {
(void)padding0__;
}
uint64_t id() const {
return flatbuffers::EndianScalar(id_);
}
int16_t count() const {
return flatbuffers::EndianScalar(count_);
}
int8_t prefix() const {
return flatbuffers::EndianScalar(prefix_);
}
uint32_t length() const {
return flatbuffers::EndianScalar(length_);
}
};
FLATBUFFERS_STRUCT_END(Foo, 16);
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Bar FLATBUFFERS_FINAL_CLASS {
private:
benchmarks_flatbuffers::Foo parent_;
int32_t time_;
float ratio_;
uint16_t size_;
int16_t padding0__; int32_t padding1__;
public:
Bar()
: parent_(),
time_(0),
ratio_(0),
size_(0),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
Bar(const benchmarks_flatbuffers::Foo &_parent, int32_t _time, float _ratio, uint16_t _size)
: parent_(_parent),
time_(flatbuffers::EndianScalar(_time)),
ratio_(flatbuffers::EndianScalar(_ratio)),
size_(flatbuffers::EndianScalar(_size)),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
const benchmarks_flatbuffers::Foo &parent() const {
return parent_;
}
int32_t time() const {
return flatbuffers::EndianScalar(time_);
}
float ratio() const {
return flatbuffers::EndianScalar(ratio_);
}
uint16_t size() const {
return flatbuffers::EndianScalar(size_);
}
};
FLATBUFFERS_STRUCT_END(Bar, 32);
struct FooBar FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef FooBarBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_SIBLING = 4,
VT_NAME = 6,
VT_RATING = 8,
VT_POSTFIX = 10
};
const benchmarks_flatbuffers::Bar *sibling() const {
return GetStruct<const benchmarks_flatbuffers::Bar *>(VT_SIBLING);
}
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
}
double rating() const {
return GetField<double>(VT_RATING, 0.0);
}
uint8_t postfix() const {
return GetField<uint8_t>(VT_POSTFIX, 0);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<benchmarks_flatbuffers::Bar>(verifier, VT_SIBLING) &&
VerifyOffset(verifier, VT_NAME) &&
verifier.VerifyString(name()) &&
VerifyField<double>(verifier, VT_RATING) &&
VerifyField<uint8_t>(verifier, VT_POSTFIX) &&
verifier.EndTable();
}
};
struct FooBarBuilder {
typedef FooBar Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_sibling(const benchmarks_flatbuffers::Bar *sibling) {
fbb_.AddStruct(FooBar::VT_SIBLING, sibling);
}
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
fbb_.AddOffset(FooBar::VT_NAME, name);
}
void add_rating(double rating) {
fbb_.AddElement<double>(FooBar::VT_RATING, rating, 0.0);
}
void add_postfix(uint8_t postfix) {
fbb_.AddElement<uint8_t>(FooBar::VT_POSTFIX, postfix, 0);
}
explicit FooBarBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<FooBar> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<FooBar>(end);
return o;
}
};
inline flatbuffers::Offset<FooBar> CreateFooBar(
flatbuffers::FlatBufferBuilder &_fbb,
const benchmarks_flatbuffers::Bar *sibling = nullptr,
flatbuffers::Offset<flatbuffers::String> name = 0,
double rating = 0.0,
uint8_t postfix = 0) {
FooBarBuilder builder_(_fbb);
builder_.add_rating(rating);
builder_.add_name(name);
builder_.add_sibling(sibling);
builder_.add_postfix(postfix);
return builder_.Finish();
}
inline flatbuffers::Offset<FooBar> CreateFooBarDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const benchmarks_flatbuffers::Bar *sibling = nullptr,
const char *name = nullptr,
double rating = 0.0,
uint8_t postfix = 0) {
auto name__ = name ? _fbb.CreateString(name) : 0;
return benchmarks_flatbuffers::CreateFooBar(
_fbb,
sibling,
name__,
rating,
postfix);
}
struct FooBarContainer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef FooBarContainerBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_LIST = 4,
VT_INITIALIZED = 6,
VT_FRUIT = 8,
VT_LOCATION = 10
};
const flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>> *list() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>> *>(VT_LIST);
}
bool initialized() const {
return GetField<uint8_t>(VT_INITIALIZED, 0) != 0;
}
benchmarks_flatbuffers::Enum fruit() const {
return static_cast<benchmarks_flatbuffers::Enum>(GetField<int16_t>(VT_FRUIT, 0));
}
const flatbuffers::String *location() const {
return GetPointer<const flatbuffers::String *>(VT_LOCATION);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_LIST) &&
verifier.VerifyVector(list()) &&
verifier.VerifyVectorOfTables(list()) &&
VerifyField<uint8_t>(verifier, VT_INITIALIZED) &&
VerifyField<int16_t>(verifier, VT_FRUIT) &&
VerifyOffset(verifier, VT_LOCATION) &&
verifier.VerifyString(location()) &&
verifier.EndTable();
}
};
struct FooBarContainerBuilder {
typedef FooBarContainer Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_list(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>> list) {
fbb_.AddOffset(FooBarContainer::VT_LIST, list);
}
void add_initialized(bool initialized) {
fbb_.AddElement<uint8_t>(FooBarContainer::VT_INITIALIZED, static_cast<uint8_t>(initialized), 0);
}
void add_fruit(benchmarks_flatbuffers::Enum fruit) {
fbb_.AddElement<int16_t>(FooBarContainer::VT_FRUIT, static_cast<int16_t>(fruit), 0);
}
void add_location(flatbuffers::Offset<flatbuffers::String> location) {
fbb_.AddOffset(FooBarContainer::VT_LOCATION, location);
}
explicit FooBarContainerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<FooBarContainer> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<FooBarContainer>(end);
return o;
}
};
inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainer(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>> list = 0,
bool initialized = false,
benchmarks_flatbuffers::Enum fruit = benchmarks_flatbuffers::Enum_Apples,
flatbuffers::Offset<flatbuffers::String> location = 0) {
FooBarContainerBuilder builder_(_fbb);
builder_.add_location(location);
builder_.add_list(list);
builder_.add_fruit(fruit);
builder_.add_initialized(initialized);
return builder_.Finish();
}
inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainerDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>> *list = nullptr,
bool initialized = false,
benchmarks_flatbuffers::Enum fruit = benchmarks_flatbuffers::Enum_Apples,
const char *location = nullptr) {
auto list__ = list ? _fbb.CreateVector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>(*list) : 0;
auto location__ = location ? _fbb.CreateString(location) : 0;
return benchmarks_flatbuffers::CreateFooBarContainer(
_fbb,
list__,
initialized,
fruit,
location__);
}
inline const benchmarks_flatbuffers::FooBarContainer *GetFooBarContainer(const void *buf) {
return flatbuffers::GetRoot<benchmarks_flatbuffers::FooBarContainer>(buf);
}
inline const benchmarks_flatbuffers::FooBarContainer *GetSizePrefixedFooBarContainer(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<benchmarks_flatbuffers::FooBarContainer>(buf);
}
inline bool VerifyFooBarContainerBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<benchmarks_flatbuffers::FooBarContainer>(nullptr);
}
inline bool VerifySizePrefixedFooBarContainerBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<benchmarks_flatbuffers::FooBarContainer>(nullptr);
}
inline void FinishFooBarContainerBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<benchmarks_flatbuffers::FooBarContainer> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedFooBarContainerBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<benchmarks_flatbuffers::FooBarContainer> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace benchmarks_flatbuffers
#endif // FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_

View File

@ -0,0 +1,81 @@
#include "benchmarks/cpp/flatbuffers/fb_bench.h"
#include <cstdint>
#include <memory>
#include "benchmarks/cpp/bench.h"
#include "benchmarks/cpp/flatbuffers/bench_generated.h"
#include "flatbuffers/flatbuffers.h"
using namespace flatbuffers;
using namespace benchmarks_flatbuffers;
namespace {
struct FlatBufferBench : Bench {
explicit FlatBufferBench(int64_t initial_size,
Allocator *allocator)
: fbb(initial_size, allocator, false) {}
uint8_t *Encode(void *, int64_t &len) override {
fbb.Clear();
const int kVectorLength = 3;
Offset<FooBar> vec[kVectorLength];
for(int i = 0; i < kVectorLength; ++i) {
Foo foo(0xABADCAFEABADCAFE + i, 10000 + i, '@' + i, 1000000 + i);
Bar bar(foo, 123456 + i, 3.14159f + i, 10000 + i);
auto name = fbb.CreateString("Hello, World!");
auto foobar = CreateFooBar(fbb, &bar, name, 3.1415432432445543543 + i,
'!' + i);
vec[i] = foobar;
}
auto location = fbb.CreateString("http://google.com/flatbuffers/");
auto foobarvec = fbb.CreateVector(vec, kVectorLength);
auto foobarcontainer = CreateFooBarContainer(fbb, foobarvec, true,
Enum_Bananas, location);
fbb.Finish(foobarcontainer);
len = fbb.GetSize();
return fbb.GetBufferPointer();
}
int64_t Use(void *decoded) override {
sum = 0;
auto foobarcontainer = GetFooBarContainer(decoded);
sum = 0;
Add(foobarcontainer->initialized());
Add(foobarcontainer->location()->Length());
Add(foobarcontainer->fruit());
for (unsigned int i = 0; i < foobarcontainer->list()->Length(); i++) {
auto foobar = foobarcontainer->list()->Get(i);
Add(foobar->name()->Length());
Add(foobar->postfix());
Add(static_cast<int64_t>(foobar->rating()));
auto bar = foobar->sibling();
Add(static_cast<int64_t>(bar->ratio()));
Add(bar->size());
Add(bar->time());
auto &foo = bar->parent();
Add(foo.count());
Add(foo.id());
Add(foo.length());
Add(foo.prefix());
}
return sum;
}
void *Decode(void *buffer, int64_t) override { return buffer; }
void Dealloc(void *) override{};
FlatBufferBuilder fbb;
};
} // namespace
std::unique_ptr<Bench> NewFlatBuffersBench(int64_t initial_size,
Allocator *allocator) {
return std::unique_ptr<FlatBufferBench>(
new FlatBufferBench(initial_size, allocator));
}

View File

@ -0,0 +1,23 @@
#ifndef BENCHMARKS_CPP_FLATBUFFERS_FB_BENCH_H_
#define BENCHMARKS_CPP_FLATBUFFERS_FB_BENCH_H_
#include <cstdint>
#include <memory>
#include "benchmarks/cpp/bench.h"
#include "include/flatbuffers/flatbuffers.h"
struct StaticAllocator : public flatbuffers::Allocator {
explicit StaticAllocator(uint8_t *buffer) : buffer_(buffer) {}
uint8_t *allocate(size_t) override { return buffer_; }
void deallocate(uint8_t *, size_t) override {}
uint8_t *buffer_;
};
std::unique_ptr<Bench> NewFlatBuffersBench(
int64_t initial_size = 1024, flatbuffers::Allocator *allocator = nullptr);
#endif // BENCHMARKS_CPP_FLATBUFFERS_FB_BENCH_H_