diff --git a/Bigfoot/Benchmarks/Engine/AssetContainer/AssetContainer.cpp b/Bigfoot/Benchmarks/Engine/AssetContainer/AssetContainer.cpp new file mode 100644 index 0000000..c6805ca --- /dev/null +++ b/Bigfoot/Benchmarks/Engine/AssetContainer/AssetContainer.cpp @@ -0,0 +1,164 @@ +#include + +#include + +#include + +#include + +#include + +namespace Bigfoot +{ +#ifdef BIGFOOT_TOOLMODE +namespace +{ +using Random = effolkronium::random_static; +} // namespace + +/****************************************************************************************/ + +void Insert(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + for (auto _: state) + { + AssetContainer container; + for (std::uint32_t i = 0; i < count; ++i) + { + benchmark::DoNotOptimize(container.Insert()); + } + benchmark::DoNotOptimize(container); + benchmark::ClobberMemory(); + } + + state.SetItemsProcessed(state.iterations() * count); +} +BENCHMARK(Insert)->Name("AssetContainer/Insert")->Arg(512)->Arg(8192)->Arg(131072); + +/****************************************************************************************/ + +void Get(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + AssetContainer container; + eastl::vector> keys; + keys.reserve(count); + for (std::uint32_t i = 0; i < count; ++i) + { + keys.push_back(container.Insert()); + } + Random::shuffle(keys); + + for (auto _: state) + { + std::uint64_t sum = 0; + for (const SlotMapKey<> key: keys) + { + if (const BenchmarkAsset* const asset = container.Get(key)) + { + sum += asset->GetHeader().type_id; + } + } + benchmark::DoNotOptimize(sum); + } + + state.SetItemsProcessed(state.iterations() * count); +} +BENCHMARK(Get)->Name("AssetContainer/Get")->Arg(512)->Arg(8192)->Arg(131072); + +/****************************************************************************************/ + +void Has(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + AssetContainer container; + eastl::vector uuids; + uuids.reserve(count); + for (std::uint32_t i = 0; i < count; ++i) + { + const SlotMapKey<> key = container.Insert(); + uuids.push_back(container.Get(key)->GetHeader().uuid); + } + Random::shuffle(uuids); + + for (auto _: state) + { + bool result = true; + for (const UUID& uuid: uuids) + { + result = result && container.Has(uuid); + } + benchmark::DoNotOptimize(result); + } + + state.SetItemsProcessed(state.iterations() * count); +} +BENCHMARK(Has)->Name("AssetContainer/Has")->Arg(512)->Arg(8192)->Arg(131072); + +/****************************************************************************************/ + +void AcquireContainerHandle(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + AssetContainer container; + eastl::vector uuids; + uuids.reserve(count); + for (std::uint32_t i = 0; i < count; ++i) + { + const SlotMapKey<> key = container.Insert(); + uuids.push_back(container.Get(key)->GetHeader().uuid); + } + Random::shuffle(uuids); + + for (auto _: state) + { + std::uint64_t sum = 0; + for (const UUID& uuid: uuids) + { + sum += container.AcquireContainerHandle(uuid)->GetHardRefCount(); + } + benchmark::DoNotOptimize(sum); + } + + state.SetItemsProcessed(state.iterations() * count); +} +BENCHMARK(AcquireContainerHandle)->Name("AssetContainer/AcquireContainerHandle")->Arg(512)->Arg(8192)->Arg(131072); + +/****************************************************************************************/ + +void Remove(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + AssetContainer container; + eastl::vector uuids; + uuids.reserve(count); + + for (auto _: state) + { + state.PauseTiming(); + uuids.clear(); + for (std::uint32_t i = 0; i < count; ++i) + { + const SlotMapKey<> key = container.Insert(); + uuids.push_back(container.Get(key)->GetHeader().uuid); + } + Random::shuffle(uuids); + state.ResumeTiming(); + + for (const UUID& uuid: uuids) + { + container.Remove(uuid); + } + } + + state.SetItemsProcessed(state.iterations() * count); +} +BENCHMARK(Remove)->Name("AssetContainer/Remove")->Arg(512)->Arg(8192)->Arg(131072); +#endif +} // namespace Bigfoot diff --git a/Bigfoot/Benchmarks/Engine/Reference/Reference.cpp b/Bigfoot/Benchmarks/Engine/Reference/Reference.cpp new file mode 100644 index 0000000..358ad4f --- /dev/null +++ b/Bigfoot/Benchmarks/Engine/Reference/Reference.cpp @@ -0,0 +1,128 @@ +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace Bigfoot +{ +#ifdef BIGFOOT_TOOLMODE +template class REFERENCE> +void Construct(benchmark::State& state) +{ + AssetLibrary library; + AssetContainer container; + std::ignore = library.Insert(&container); + ScopedActiveAssetLibrary scopedLibrary {&library}; + + const SlotMapKey<> key = container.Insert(); + const UUID uuid = container.Get(key)->GetHeader().uuid; + + for (auto _: state) + { + REFERENCE reference {uuid}; + benchmark::DoNotOptimize(reference); + } + + state.SetItemsProcessed(state.iterations()); +} +BENCHMARK_TEMPLATE(Construct, HardReference)->Name("Reference/HardReference/Construct"); +BENCHMARK_TEMPLATE(Construct, SoftReference)->Name("Reference/SoftReference/Construct"); + +/****************************************************************************************/ + +template class REFERENCE> +void Get(benchmark::State& state) +{ + AssetLibrary library; + AssetContainer container; + std::ignore = library.Insert(&container); + ScopedActiveAssetLibrary scopedLibrary {&library}; + + const SlotMapKey<> key = container.Insert(); + const UUID uuid = container.Get(key)->GetHeader().uuid; + + REFERENCE reference {uuid}; + + for (auto _: state) + { + benchmark::DoNotOptimize(reference.Get()); + } + + state.SetItemsProcessed(state.iterations()); +} +BENCHMARK_TEMPLATE(Get, HardReference)->Name("Reference/HardReference/Get"); +BENCHMARK_TEMPLATE(Get, SoftReference)->Name("Reference/SoftReference/Get"); + +/****************************************************************************************/ + +template class REFERENCE> +void Copy(benchmark::State& state) +{ + AssetLibrary library; + AssetContainer container; + std::ignore = library.Insert(&container); + ScopedActiveAssetLibrary scopedLibrary {&library}; + + const SlotMapKey<> key = container.Insert(); + const UUID uuid = container.Get(key)->GetHeader().uuid; + + REFERENCE reference {uuid}; + + for (auto _: state) + { + REFERENCE copy {reference}; + benchmark::DoNotOptimize(copy); + } + + state.SetItemsProcessed(state.iterations()); +} +BENCHMARK_TEMPLATE(Copy, HardReference)->Name("Reference/HardReference/Copy"); +BENCHMARK_TEMPLATE(Copy, SoftReference)->Name("Reference/SoftReference/Copy"); + +/****************************************************************************************/ + +template class REFERENCE> +void Move(benchmark::State& state) +{ + AssetLibrary library; + AssetContainer container; + std::ignore = library.Insert(&container); + ScopedActiveAssetLibrary scopedLibrary {&library}; + + const SlotMapKey<> key = container.Insert(); + const UUID uuid = container.Get(key)->GetHeader().uuid; + + constexpr std::size_t BATCH_SIZE = 128; + eastl::vector> batch; + batch.reserve(BATCH_SIZE); + + for (auto _: state) + { + state.PauseTiming(); + batch.clear(); + for (std::size_t i = 0; i < BATCH_SIZE; ++i) + { + batch.emplace_back(uuid); + } + state.ResumeTiming(); + + for (REFERENCE& reference: batch) + { + REFERENCE moved {std::move(reference)}; + benchmark::DoNotOptimize(moved); + } + } + + state.SetItemsProcessed(state.iterations() * BATCH_SIZE); +} +BENCHMARK_TEMPLATE(Move, HardReference)->Name("Reference/HardReference/Move"); +BENCHMARK_TEMPLATE(Move, SoftReference)->Name("Reference/SoftReference/Move"); +#endif +} // namespace Bigfoot diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp index 1cedcf4..a0fa807 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp @@ -164,7 +164,7 @@ class AssetContainerBase [[nodiscard]] ContainerHandle* AcquireContainerHandle(const UUID& p_uuid) { - return m_handles.Get(GetOrCreateEntry(p_uuid).m_handleSlotKey); + return GetOrCreateEntry(p_uuid).m_handle; } /* @@ -174,7 +174,7 @@ class AssetContainerBase */ virtual void Remove(const UUID& p_uuid) { - if (Entry* entry = FindEntry(p_uuid); entry != nullptr && entry->m_handleSlotKey.Valid()) + if (Entry* entry = FindEntry(p_uuid); entry != nullptr) { m_handles.Remove(entry->m_handleSlotKey); m_uuidToEntry.erase(p_uuid); @@ -195,6 +195,11 @@ class AssetContainerBase * SlotMapKey to the asset */ SlotMapKey m_assetSlotKey; + + /* + * The handle itself, cached to avoid a SlotMap lookup on every access + */ + ContainerHandle* m_handle = nullptr; }; AssetContainerBase() = default; @@ -241,23 +246,12 @@ class AssetContainerBase if (inserted) { it->second.m_handleSlotKey = m_handles.Insert(); + it->second.m_handle = m_handles.Get(it->second.m_handleSlotKey); } return it->second; } - /* - * Get a ContainerHandle - * - * \param p_handleSlotKey The key to the container - * \return The container - */ - [[nodiscard]] - ContainerHandle& FindContainerHandle(const SlotMapKey p_handleSlotKey) - { - return *m_handles.Get(p_handleSlotKey); - } - private: /* * HandleContainers @@ -267,7 +261,7 @@ class AssetContainerBase /* * Every Asset added to the map */ - ankerl::unordered_dense::segmented_map m_uuidToEntry; + ankerl::unordered_dense::map m_uuidToEntry; }; /****************************************************************************************/ @@ -303,7 +297,7 @@ class AssetContainer: public AssetContainerBase else { entry.m_assetSlotKey = slotKey; - FindContainerHandle(entry.m_handleSlotKey).SetAsset(asset); + entry.m_handle->SetAsset(asset); } return slotKey; @@ -342,7 +336,7 @@ class AssetContainer: public AssetContainerBase { if (Entry* entry = FindEntry(p_uuid); entry != nullptr && entry->m_assetSlotKey.Valid()) { - FindContainerHandle(entry->m_handleSlotKey).SetAsset(nullptr); + entry->m_handle->SetAsset(nullptr); m_assets.Remove(entry->m_assetSlotKey); entry->m_assetSlotKey = SlotMapKey {}; } diff --git a/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp b/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp index 9cdc86d..b84e225 100644 --- a/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp +++ b/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp @@ -9,6 +9,8 @@ #include #include +#include + namespace Bigfoot { class UUID @@ -112,6 +114,23 @@ struct std::hash } }; +/****************************************************************************************/ + +template<> +struct ankerl::unordered_dense::hash +{ + using is_avalanching = void; + + [[nodiscard]] + std::uint64_t operator()(const Bigfoot::UUID& p_uuid) const noexcept + { + const auto bytes = p_uuid.ToBytes(); + return detail::wyhash::hash(bytes.data(), bytes.size()); + } +}; + +/****************************************************************************************/ + template<> struct fmt::formatter {