BigFile/Sasquatch #1

Merged
rboullard merged 100 commits from BigFile into Development 2026-09-01 16:32:02 +00:00
3 changed files with 376 additions and 10 deletions
Showing only changes of commit 515bb92d13 - Show all commits
@@ -116,7 +116,7 @@ BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffer)(benchmark::State& state)
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer");
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer")->UseRealTime();
/****************************************************************************************/
@@ -153,7 +153,8 @@ BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffers)
->Arg(8)
->Arg(64)
->Arg(512)
->Arg(4096);
->Arg(4096)
->UseRealTime();
/****************************************************************************************/
@@ -168,7 +169,7 @@ BENCHMARK_DEFINE_F(BigFileFixture, GetAssetHardReferences)(benchmark::State& sta
state.SetItemsProcessed(state.iterations());
}
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetHardReferences)->Name("BigFile/GetAssetHardReferences");
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetHardReferences)->Name("BigFile/GetAssetHardReferences")->UseRealTime();
/****************************************************************************************/
@@ -195,7 +196,8 @@ BENCHMARK_REGISTER_F(BigFileFixture, GetAssetsHardReferences)
->Arg(8)
->Arg(64)
->Arg(512)
->Arg(4096);
->Arg(4096)
->UseRealTime();
/****************************************************************************************/
@@ -222,7 +224,7 @@ BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffer)(benchmark::State& state)
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer");
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer")->UseRealTime();
/****************************************************************************************/
@@ -265,6 +267,7 @@ BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffers)
->Arg(8)
->Arg(64)
->Arg(512)
->Arg(4096);
->Arg(4096)
->UseRealTime();
#endif
} // namespace Bigfoot
@@ -151,7 +151,7 @@ BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetHardReferences)(benchmark::State& s
state.SetItemsProcessed(state.iterations());
}
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetHardReferences)->Name("Sasquatch/GetAssetHardReferences");
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetHardReferences)->Name("Sasquatch/GetAssetHardReferences")->UseRealTime();
/****************************************************************************************/
@@ -178,7 +178,8 @@ BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetsHardReferences)
->Arg(8)
->Arg(64)
->Arg(512)
->Arg(4096);
->Arg(4096)
->UseRealTime();
/****************************************************************************************/
@@ -199,7 +200,7 @@ BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffer)(benchmark::State& state
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffer)->Name("Sasquatch/GetAssetFlatbuffer");
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffer)->Name("Sasquatch/GetAssetFlatbuffer")->UseRealTime();
/****************************************************************************************/
@@ -236,6 +237,7 @@ BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffers)
->Arg(8)
->Arg(64)
->Arg(512)
->Arg(4096);
->Arg(4096)
->UseRealTime();
#endif
} // namespace Bigfoot
@@ -0,0 +1,361 @@
/*********************************************************************
* \file SerializationManager.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <Engine/SerializationManager/SerializationManager.hpp>
#include <Engine/Asset/AssetLibrary.hpp>
#include <Engine/DataAccessor/DataAccessor.hpp>
#if defined BIGFOOT_TOOLMODE
#include <Engine/BigFile/BigFile.hpp>
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
#elif defined BIGFOOT_GAME
#include <Engine/Sasquatch/Sasquatch.hpp>
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
#endif
#include <System/File/File.hpp>
#include <System/UUID/UUID.hpp>
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
#include <EASTL/optional.h>
#include <EASTL/vector.h>
#include <ankerl/unordered_dense.h>
#include <benchmark/benchmark.h>
#include <effolkronium/random.hpp>
#include <cstddef>
#include <cstdint>
#include <tuple>
namespace Bigfoot
{
using Random = effolkronium::random_static;
class SerializationManagerFixture: public benchmark::Fixture
{
protected:
static constexpr std::uint32_t ROOT_ASSET_COUNT = 20'000;
static constexpr std::uint32_t REFS_PER_ROOT = 4;
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
void SetUp(benchmark::State&) override
{
m_previousDataAccessor = g_dataAccessor;
m_previousAssetLibrary = g_activeAssetLibrary;
m_rootUuids.clear();
m_rootUuids.reserve(ROOT_ASSET_COUNT);
m_leafUuids.clear();
m_leafUuids.reserve(ROOT_ASSET_COUNT * REFS_PER_ROOT);
eastl::vector<UUID> uuids;
eastl::vector<eastl::vector<std::byte>> flatbuffers;
eastl::vector<eastl::vector<UUID>> hardReferences;
uuids.reserve(ROOT_ASSET_COUNT * (1 + REFS_PER_ROOT));
flatbuffers.reserve(uuids.capacity());
hardReferences.reserve(uuids.capacity());
m_rootTotalBytes.clear();
m_rootTotalBytes.reserve(ROOT_ASSET_COUNT);
for (std::uint32_t i = 0; i < ROOT_ASSET_COUNT; ++i)
{
BenchmarkAsset root;
root.SetName(root.GetHeader().uuid.ToString().c_str());
root.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
std::size_t totalBytes = 0;
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
{
BenchmarkAssetReferred leaf;
leaf.SetName(leaf.GetHeader().uuid.ToString().c_str());
root.GetAsset().refs.emplace_back(leaf.GetHeader().uuid);
const eastl::vector<std::byte> leafFlatbuffer = leaf.Pack();
totalBytes += leafFlatbuffer.size();
m_leafUuids.push_back(leaf.GetHeader().uuid);
uuids.push_back(leaf.GetHeader().uuid);
hardReferences.push_back(leaf.GetHardReferences(leafFlatbuffer));
flatbuffers.push_back(leafFlatbuffer);
}
const eastl::vector<std::byte> rootFlatbuffer = root.Pack();
totalBytes += rootFlatbuffer.size();
m_rootTotalBytes.emplace(root.GetHeader().uuid, totalBytes);
m_rootUuids.push_back(root.GetHeader().uuid);
uuids.push_back(root.GetHeader().uuid);
hardReferences.push_back(root.GetHardReferences(rootFlatbuffer));
flatbuffers.push_back(rootFlatbuffer);
}
#if defined BIGFOOT_TOOLMODE
m_bigFile.emplace(File {BIGFILE_ENGINEBENCHMARKS_LOCATION});
m_bigFile->Clear();
m_bigFile->SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
SetDataAccessor(&*m_bigFile);
#elif defined BIGFOOT_GAME
std::size_t totalFlatbufferBytes = 0;
std::size_t totalHardReferencesBytes = 0;
for (std::size_t i = 0; i < uuids.size(); ++i)
{
totalFlatbufferBytes += flatbuffers[i].size();
totalHardReferencesBytes += hardReferences[i].size() * UUID::UUID_BYTE_SIZE;
}
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
{
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION},
uuids.size(),
totalFlatbufferBytes,
totalHardReferencesBytes};
for (std::size_t i = 0; i < uuids.size(); ++i)
{
writer.WriteAsset(uuids[i], flatbuffers[i], hardReferences[i]);
}
}
m_sasquatch.emplace(File {SASQUATCH_ENGINEBENCHMARKS_LOCATION});
SetDataAccessor(&*m_sasquatch);
#endif
}
void TearDown(benchmark::State&) override
{
#if defined BIGFOOT_TOOLMODE
m_bigFile.reset();
#elif defined BIGFOOT_GAME
m_sasquatch.reset();
#endif
SetDataAccessor(m_previousDataAccessor);
SetActiveAssetLibrary(m_previousAssetLibrary);
}
/*
* Registers a fresh, empty AssetLibrary as the active one, so that every root and leaf asset appears unloaded
*
* \param p_library The library to register
* \param p_leafContainer The container to register leaves into
* \param p_rootContainer The container to register roots into
*/
static void ResetActiveLibrary(AssetLibrary& p_library,
AssetContainer<BenchmarkAssetReferred>& p_leafContainer,
AssetContainer<BenchmarkAsset>& p_rootContainer)
{
std::ignore = p_library.Insert(&p_leafContainer);
std::ignore = p_library.Insert(&p_rootContainer);
SetActiveAssetLibrary(&p_library);
}
[[nodiscard]]
eastl::vector<UUID> RandomRootBatch(const std::size_t p_batchSize) const
{
eastl::vector<UUID> batch;
batch.reserve(p_batchSize);
for (std::size_t i = 0; i < p_batchSize; ++i)
{
batch.push_back(m_rootUuids[Random::get<std::size_t>(0, m_rootUuids.size() - 1)]);
}
return batch;
}
/*
* Total flatbuffer bytes (root + its leaves) that loading p_roots will actually read, deduplicated the same way
* SerializationManager::LoadAssets deduplicates its own transitive discovery
*
* \param p_roots The root assets that would be loaded
* \return The total flatbuffer bytes across the unique roots
*/
[[nodiscard]]
std::int64_t TotalBytes(const eastl::vector<UUID>& p_roots) const
{
ankerl::unordered_dense::set<UUID> unique;
unique.reserve(p_roots.size());
for (const UUID& uuid: p_roots)
{
unique.insert(uuid);
}
std::int64_t bytes = 0;
for (const UUID& uuid: unique)
{
bytes += static_cast<std::int64_t>(m_rootTotalBytes.at(uuid));
}
return bytes;
}
DataAccessor* m_previousDataAccessor = nullptr;
AssetLibrary* m_previousAssetLibrary = nullptr;
eastl::vector<UUID> m_rootUuids;
eastl::vector<UUID> m_leafUuids;
ankerl::unordered_dense::map<UUID, std::size_t> m_rootTotalBytes;
#if defined BIGFOOT_TOOLMODE
eastl::optional<BigFile> m_bigFile;
#elif defined BIGFOOT_GAME
eastl::optional<Sasquatch> m_sasquatch;
#endif
};
/****************************************************************************************/
BENCHMARK_DEFINE_F(SerializationManagerFixture, LoadAsset)(benchmark::State& state)
{
std::int64_t bytesProcessed = 0;
for (auto _: state)
{
state.PauseTiming();
AssetLibrary library;
// leafContainer must outlive rootContainer: the loaded root's HardReferences release into leafContainer's
// handles on destruction, so declaring it second would tear it down first and use-after-free those handles.
AssetContainer<BenchmarkAssetReferred> leafContainer;
AssetContainer<BenchmarkAsset> rootContainer;
ResetActiveLibrary(library, leafContainer, rootContainer);
const UUID uuid = m_rootUuids[Random::get<std::size_t>(0, m_rootUuids.size() - 1)];
const std::size_t uuidBytes = m_rootTotalBytes.at(uuid);
state.ResumeTiming();
SerializationManager::LoadAsset(uuid);
bytesProcessed += static_cast<std::int64_t>(uuidBytes);
}
state.SetItemsProcessed(state.iterations() * (1 + REFS_PER_ROOT));
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SerializationManagerFixture, LoadAsset)->Name("SerializationManager/LoadAsset")->UseRealTime();
/****************************************************************************************/
BENCHMARK_DEFINE_F(SerializationManagerFixture, LoadAssets)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
std::int64_t bytesProcessed = 0;
for (auto _: state)
{
state.PauseTiming();
AssetLibrary library;
// leafContainer must outlive rootContainer, see the same comment in the LoadAsset benchmark above.
AssetContainer<BenchmarkAssetReferred> leafContainer;
AssetContainer<BenchmarkAsset> rootContainer;
ResetActiveLibrary(library, leafContainer, rootContainer);
const eastl::vector<UUID> batch = RandomRootBatch(batchSize);
const std::int64_t batchBytes = TotalBytes(batch);
state.ResumeTiming();
SerializationManager::LoadAssets(batch);
bytesProcessed += batchBytes;
}
state.SetItemsProcessed(state.iterations() * batchSize * (1 + REFS_PER_ROOT));
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SerializationManagerFixture, LoadAssets)
->Name("SerializationManager/LoadAssets")
->Arg(1)
->Arg(8)
->Arg(64)
->Arg(512)
->UseRealTime();
/****************************************************************************************/
#if defined BIGFOOT_TOOLMODE
BENCHMARK_DEFINE_F(SerializationManagerFixture, SaveAsset)(benchmark::State& state)
{
AssetLibrary library;
AssetContainer<BenchmarkAsset> container;
std::ignore = library.Insert(&container);
SetActiveAssetLibrary(&library);
std::int64_t bytesProcessed = 0;
for (auto _: state)
{
state.PauseTiming();
auto* asset = static_cast<BenchmarkAsset*>(container.Insert()->GetAsset());
asset->SetName(asset->GetHeader().uuid.ToString().c_str());
asset->GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
{
asset->GetAsset().refs.emplace_back(m_leafUuids[Random::get<std::size_t>(0, m_leafUuids.size() - 1)]);
}
const UUID uuid = asset->GetHeader().uuid;
const std::size_t assetBytes = asset->Pack().size();
state.ResumeTiming();
benchmark::DoNotOptimize(SerializationManager::SaveAsset(uuid));
bytesProcessed += static_cast<std::int64_t>(assetBytes);
}
state.SetItemsProcessed(state.iterations());
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SerializationManagerFixture, SaveAsset)->Name("SerializationManager/SaveAsset")->UseRealTime();
/****************************************************************************************/
BENCHMARK_DEFINE_F(SerializationManagerFixture, SaveAssets)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
AssetLibrary library;
AssetContainer<BenchmarkAsset> container;
std::ignore = library.Insert(&container);
SetActiveAssetLibrary(&library);
std::int64_t bytesProcessed = 0;
for (auto _: state)
{
state.PauseTiming();
eastl::vector<UUID> uuids;
uuids.reserve(batchSize);
std::size_t batchBytes = 0;
for (std::size_t i = 0; i < batchSize; ++i)
{
auto* asset = static_cast<BenchmarkAsset*>(container.Insert()->GetAsset());
asset->SetName(asset->GetHeader().uuid.ToString().c_str());
asset->GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
asset->GetAsset().refs.emplace_back(m_leafUuids[Random::get<std::size_t>(0, m_leafUuids.size() - 1)]);
batchBytes += asset->Pack().size();
uuids.push_back(asset->GetHeader().uuid);
}
state.ResumeTiming();
benchmark::DoNotOptimize(SerializationManager::SaveAssets(uuids));
bytesProcessed += static_cast<std::int64_t>(batchBytes);
}
state.SetItemsProcessed(state.iterations() * batchSize);
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SerializationManagerFixture, SaveAssets)
->Name("SerializationManager/SaveAssets")
->Arg(1)
->Arg(8)
->Arg(64)
->Arg(512)
->UseRealTime();
#endif
} // namespace Bigfoot