BigFile/Sasquatch #1
@@ -0,0 +1,164 @@
|
||||
#include <Engine/Asset/AssetContainer.hpp>
|
||||
|
||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||
|
||||
#include <effolkronium/random.hpp>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
#ifdef BIGFOOT_TOOLMODE
|
||||
namespace
|
||||
{
|
||||
using Random = effolkronium::random_static;
|
||||
} // namespace
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
void Insert(benchmark::State& state)
|
||||
{
|
||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||
|
||||
for (auto _: state)
|
||||
{
|
||||
AssetContainer<BenchmarkAsset> 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<std::uint32_t>(state.range(0));
|
||||
|
||||
AssetContainer<BenchmarkAsset> container;
|
||||
eastl::vector<SlotMapKey<>> 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<std::uint32_t>(state.range(0));
|
||||
|
||||
AssetContainer<BenchmarkAsset> container;
|
||||
eastl::vector<UUID> 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<std::uint32_t>(state.range(0));
|
||||
|
||||
AssetContainer<BenchmarkAsset> container;
|
||||
eastl::vector<UUID> 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<std::uint32_t>(state.range(0));
|
||||
|
||||
AssetContainer<BenchmarkAsset> container;
|
||||
eastl::vector<UUID> 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
|
||||
@@ -0,0 +1,128 @@
|
||||
#include <Engine/Asset/AssetLibrary.hpp>
|
||||
#include <Engine/Asset/Reference.hpp>
|
||||
|
||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
#ifdef BIGFOOT_TOOLMODE
|
||||
template<template<class> class REFERENCE>
|
||||
void Construct(benchmark::State& state)
|
||||
{
|
||||
AssetLibrary library;
|
||||
AssetContainer<BenchmarkAsset> 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<BenchmarkAsset> 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<template<class> class REFERENCE>
|
||||
void Get(benchmark::State& state)
|
||||
{
|
||||
AssetLibrary library;
|
||||
AssetContainer<BenchmarkAsset> container;
|
||||
std::ignore = library.Insert(&container);
|
||||
ScopedActiveAssetLibrary scopedLibrary {&library};
|
||||
|
||||
const SlotMapKey<> key = container.Insert();
|
||||
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
||||
|
||||
REFERENCE<BenchmarkAsset> 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<template<class> class REFERENCE>
|
||||
void Copy(benchmark::State& state)
|
||||
{
|
||||
AssetLibrary library;
|
||||
AssetContainer<BenchmarkAsset> container;
|
||||
std::ignore = library.Insert(&container);
|
||||
ScopedActiveAssetLibrary scopedLibrary {&library};
|
||||
|
||||
const SlotMapKey<> key = container.Insert();
|
||||
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
||||
|
||||
REFERENCE<BenchmarkAsset> reference {uuid};
|
||||
|
||||
for (auto _: state)
|
||||
{
|
||||
REFERENCE<BenchmarkAsset> 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<template<class> class REFERENCE>
|
||||
void Move(benchmark::State& state)
|
||||
{
|
||||
AssetLibrary library;
|
||||
AssetContainer<BenchmarkAsset> 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<REFERENCE<BenchmarkAsset>> 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<BenchmarkAsset>& reference: batch)
|
||||
{
|
||||
REFERENCE<BenchmarkAsset> 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
|
||||
@@ -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<UUID, Entry> m_uuidToEntry;
|
||||
ankerl::unordered_dense::map<UUID, Entry> 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 {};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <fmt/format.h>
|
||||
#include <uuid.h>
|
||||
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
class UUID
|
||||
@@ -112,6 +114,23 @@ struct std::hash<Bigfoot::UUID>
|
||||
}
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
template<>
|
||||
struct ankerl::unordered_dense::hash<Bigfoot::UUID>
|
||||
{
|
||||
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<Bigfoot::UUID>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user