From 0b49aa0c7eca736871488009254b31356c9a32ce Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Mon, 4 Dec 2023 08:33:07 -0500 Subject: memory usage estimation for memcached entries (#586) * do a more accurate memory usage estimation for memcached entries * early exit when checking memcache usage --- src/zenserver/cache/cachedisklayer.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src/zenserver/cache/cachedisklayer.cpp') diff --git a/src/zenserver/cache/cachedisklayer.cpp b/src/zenserver/cache/cachedisklayer.cpp index 2c344dd1d..05eb9658b 100644 --- a/src/zenserver/cache/cachedisklayer.cpp +++ b/src/zenserver/cache/cachedisklayer.cpp @@ -209,6 +209,9 @@ namespace { zen::Sleep(100); } while (true); } + + uint64_t EstimateMemCachePayloadMemory(uint64_t PayloadSize) { return 8u + 32u + RoundUp(PayloadSize, 8u); } + } // namespace namespace fs = std::filesystem; @@ -1289,14 +1292,26 @@ ZenCacheDiskLayer::CacheBucket::MemCacheTrim(GcClock::TimePoint ExpireTime) GcClock::Tick ExpireTicks = ExpireTime.time_since_epoch().count(); RwLock::ExclusiveLockScope _(m_IndexLock); + if (m_MemCachedPayloads.empty()) + { + return; + } for (const auto& Kv : m_Index) { - if (m_AccessTimes[Kv.second] < ExpireTicks) + size_t Index = Kv.second; + BucketPayload& Payload = m_Payloads[Index]; + if (!Payload.MemCached) + { + continue; + } + if (m_AccessTimes[Index] < ExpireTicks) { - BucketPayload& Payload = m_Payloads[Kv.second]; RemoveMemCachedData(Payload); } } + m_MemCachedPayloads.shrink_to_fit(); + m_FreeMemCachedPayloads.shrink_to_fit(); + m_FreeMetaDatas.shrink_to_fit(); } void @@ -1305,6 +1320,10 @@ ZenCacheDiskLayer::CacheBucket::GetUsageByAccess(GcClock::TimePoint TickStart, std::vector& InOutUsageSlots) { RwLock::SharedLockScope _(m_IndexLock); + if (m_MemCachedPayloads.empty()) + { + return; + } for (const auto& It : m_Index) { size_t Index = It.second; @@ -2630,7 +2649,7 @@ ZenCacheDiskLayer::CacheBucket::SetMemCachedData(BucketPayload& Payload, IoBuffe { Payload.MemCached = MemCachedIndex(gsl::narrow(m_MemCachedPayloads.size())); m_MemCachedPayloads.push_back(MemCachedData); - AddMemCacheUsage(PayloadSize); + AddMemCacheUsage(EstimateMemCachePayloadMemory(PayloadSize)); m_MemoryWriteCount++; } } @@ -2639,7 +2658,7 @@ ZenCacheDiskLayer::CacheBucket::SetMemCachedData(BucketPayload& Payload, IoBuffe Payload.MemCached = m_FreeMemCachedPayloads.back(); m_FreeMemCachedPayloads.pop_back(); m_MemCachedPayloads[Payload.MemCached] = MemCachedData; - AddMemCacheUsage(PayloadSize); + AddMemCacheUsage(EstimateMemCachePayloadMemory(PayloadSize)); m_MemoryWriteCount++; } } @@ -2650,7 +2669,7 @@ ZenCacheDiskLayer::CacheBucket::RemoveMemCachedData(BucketPayload& Payload) if (Payload.MemCached) { size_t PayloadSize = m_MemCachedPayloads[Payload.MemCached].GetSize(); - RemoveMemCacheUsage(PayloadSize); + RemoveMemCacheUsage(EstimateMemCachePayloadMemory(PayloadSize)); m_MemCachedPayloads[Payload.MemCached] = IoBuffer{}; m_FreeMemCachedPayloads.push_back(Payload.MemCached); Payload.MemCached = {}; -- cgit v1.2.3 From 8269e0616cf4333fd1007ccd8a7b1dac09743e11 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Mon, 4 Dec 2023 08:37:05 -0500 Subject: reserve vectors in gcv2 upfront / load factor for robin_map (#582) * reserve vectors in gcv2 upfront * set max load factor for robin_map indexes to reduce memory usage * set min load factor for robin_map indexes to allow them to shrink --- src/zenserver/cache/cachedisklayer.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src/zenserver/cache/cachedisklayer.cpp') diff --git a/src/zenserver/cache/cachedisklayer.cpp b/src/zenserver/cache/cachedisklayer.cpp index 05eb9658b..a4a37b0af 100644 --- a/src/zenserver/cache/cachedisklayer.cpp +++ b/src/zenserver/cache/cachedisklayer.cpp @@ -658,6 +658,9 @@ BucketManifestSerializer::WriteSidecarFile(const std::filesystem::path& ////////////////////////////////////////////////////////////////////////// +static const float IndexMinLoadFactor = 0.2f; +static const float IndexMaxLoadFactor = 0.7f; + ZenCacheDiskLayer::CacheBucket::CacheBucket(GcManager& Gc, std::atomic_uint64_t& OuterCacheMemoryUsage, std::string BucketName, @@ -668,6 +671,9 @@ ZenCacheDiskLayer::CacheBucket::CacheBucket(GcManager& Gc, , m_Configuration(Config) , m_BucketId(Oid::Zero) { + m_Index.min_load_factor(IndexMinLoadFactor); + m_Index.max_load_factor(IndexMaxLoadFactor); + if (m_BucketName.starts_with(std::string_view("legacy")) || m_BucketName.ends_with(std::string_view("shadermap"))) { const uint64_t LegacyOverrideSize = 16 * 1024 * 1024; @@ -2863,7 +2869,8 @@ public: m_Bucket.m_IndexLock.WithExclusiveLock([&]() { m_Bucket.m_UpdatedKeys = std::make_unique(); }); auto __ = MakeGuard([&]() { m_Bucket.m_IndexLock.WithExclusiveLock([&]() { m_Bucket.m_UpdatedKeys.reset(); }); }); - std::unordered_map BlockUsage; + size_t InlineEntryCount = 0; + BlockStore::BlockUsageMap BlockUsage; { RwLock::SharedLockScope ___(m_Bucket.m_IndexLock); for (const auto& Entry : m_Bucket.m_Index) @@ -2876,15 +2883,17 @@ public: { continue; } + InlineEntryCount++; uint32_t BlockIndex = Loc.Location.BlockLocation.GetBlockIndex(); uint64_t ChunkSize = RoundUp(Loc.Size(), m_Bucket.m_Configuration.PayloadAlignment); if (auto It = BlockUsage.find(BlockIndex); It != BlockUsage.end()) { - It->second += ChunkSize; + It->second.EntryCount++; + It->second.DiskUsage += ChunkSize; } else { - BlockUsage.insert_or_assign(BlockIndex, ChunkSize); + BlockUsage.insert_or_assign(BlockIndex, BlockStore::BlockUsageInfo{.DiskUsage = ChunkSize, .EntryCount = 1}); } } } @@ -2892,8 +2901,9 @@ public: { BlockStoreCompactState BlockCompactState; std::vector BlockCompactStateKeys; + BlockCompactStateKeys.reserve(InlineEntryCount); - std::vector BlocksToCompact = + BlockStore::BlockEntryCountMap BlocksToCompact = m_Bucket.m_BlockStore.GetBlocksToCompact(BlockUsage, Ctx.Settings.CompactBlockUsageThresholdPercent); BlockCompactState.IncludeBlocks(BlocksToCompact); @@ -3168,7 +3178,7 @@ public: uint32_t Size; }; std::vector> EntriesPerBlock; - + size_t UpdateCount = 0; { RwLock::SharedLockScope IndexLock(m_CacheBucket.m_IndexLock); for (const auto& Entry : m_CacheBucket.m_Index) @@ -3193,6 +3203,7 @@ public: { continue; } + UpdateCount++; const IoHash& Key = Entry.first; if (Loc.IsFlagSet(DiskLocation::kStandaloneFile)) { @@ -3219,6 +3230,8 @@ public: } } + UpdateKeys.reserve(UpdateCount); + for (auto It : BlockIndexToEntriesPerBlockIndex) { uint32_t BlockIndex = It.first; @@ -3671,6 +3684,8 @@ ZenCacheDiskLayer::CacheBucket::CompactState(std::vector& Payloa FirstReferenceIndex.reserve(EntryCount); } Index.reserve(EntryCount); + Index.min_load_factor(IndexMinLoadFactor); + Index.max_load_factor(IndexMaxLoadFactor); for (auto It : m_Index) { PayloadIndex EntryIndex = PayloadIndex(Payloads.size()); -- cgit v1.2.3 From 4aa1b4d6e3312e72952d26ccd702209e7051e258 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Tue, 5 Dec 2023 16:21:47 -0500 Subject: Use correct iterator index when looking up memcached payload in GatherReferences (#591) * Use correct iterator index when looking up memcached payload in gatherreferences --- src/zenserver/cache/cachedisklayer.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/zenserver/cache/cachedisklayer.cpp') diff --git a/src/zenserver/cache/cachedisklayer.cpp b/src/zenserver/cache/cachedisklayer.cpp index a4a37b0af..700529443 100644 --- a/src/zenserver/cache/cachedisklayer.cpp +++ b/src/zenserver/cache/cachedisklayer.cpp @@ -1954,10 +1954,9 @@ ZenCacheDiskLayer::CacheBucket::GatherReferences(GcContext& GcCtx) for (const auto& Entry : StructuredItemsWithUnknownAttachments) { - const IoHash& Key = Entry.first; - size_t PayloadIndex = Entry.second; - BucketPayload& Payload = Payloads[PayloadIndex]; - const DiskLocation& Loc = Payload.Location; + const IoHash& Key = Entry.first; + BucketPayload& Payload = Payloads[Entry.second]; + const DiskLocation& Loc = Payload.Location; { IoBuffer Buffer; if (Loc.IsFlagSet(DiskLocation::kStandaloneFile)) @@ -1980,7 +1979,7 @@ ZenCacheDiskLayer::CacheBucket::GatherReferences(GcContext& GcCtx) #endif // CALCULATE_BLOCKING_TIME if (auto It = m_Index.find(Key); It != m_Index.end()) { - const BucketPayload& CachedPayload = Payloads[PayloadIndex]; + const BucketPayload& CachedPayload = Payloads[It->second]; if (CachedPayload.MemCached) { Buffer = m_MemCachedPayloads[CachedPayload.MemCached]; -- cgit v1.2.3