1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 12:06:01 +01:00

Reduce false sharing between pathInfoCache and Store

`perf c2c` shows a lot of cacheline conflicts between purely read-only
Store methods (like `parseStorePath()`) and the Sync classes. So
allocate pathInfoCache separately to avoid that.
This commit is contained in:
Eelco Dolstra 2025-09-04 11:54:59 +02:00
parent 5ae1b5f88b
commit a73cf447ac
7 changed files with 37 additions and 63 deletions

View file

@ -125,11 +125,8 @@ void BinaryCacheStore::writeNarInfo(ref<NarInfo> narInfo)
upsertFile(narInfoFile, narInfo->to_string(*this), "text/x-nix-narinfo"); upsertFile(narInfoFile, narInfo->to_string(*this), "text/x-nix-narinfo");
{ pathInfoCache->lock()->upsert(
auto state_(state.lock());
state_->pathInfoCache.upsert(
std::string(narInfo->path.to_string()), PathInfoCacheValue{.value = std::shared_ptr<NarInfo>(narInfo)}); std::string(narInfo->path.to_string()), PathInfoCacheValue{.value = std::shared_ptr<NarInfo>(narInfo)});
}
if (diskCache) if (diskCache)
diskCache->upsertNarInfo( diskCache->upsertNarInfo(

View file

@ -310,14 +310,11 @@ protected:
} }
}; };
struct State
{
LRUCache<std::string, PathInfoCacheValue> pathInfoCache;
};
void invalidatePathInfoCacheFor(const StorePath & path); void invalidatePathInfoCacheFor(const StorePath & path);
SharedSync<State> state; // Note: this is a `ref` to avoid false sharing with immutable
// bits of `Store`.
ref<SharedSync<LRUCache<std::string, PathInfoCacheValue>>> pathInfoCache;
std::shared_ptr<NarInfoDiskCache> diskCache; std::shared_ptr<NarInfoDiskCache> diskCache;
@ -860,7 +857,7 @@ public:
*/ */
void clearPathInfoCache() void clearPathInfoCache()
{ {
state.lock()->pathInfoCache.clear(); pathInfoCache->lock()->clear();
} }
/** /**

View file

@ -716,12 +716,8 @@ uint64_t LocalStore::addValidPath(State & state, const ValidPathInfo & info, boo
} }
} }
{ pathInfoCache->lock()->upsert(
auto state_(Store::state.lock()); std::string(info.path.to_string()), PathInfoCacheValue{.value = std::make_shared<const ValidPathInfo>(info)});
state_->pathInfoCache.upsert(
std::string(info.path.to_string()),
PathInfoCacheValue{.value = std::make_shared<const ValidPathInfo>(info)});
}
return id; return id;
} }
@ -1023,10 +1019,7 @@ void LocalStore::invalidatePath(State & state, const StorePath & path)
/* Note that the foreign key constraints on the Refs table take /* Note that the foreign key constraints on the Refs table take
care of deleting the references entries for `path'. */ care of deleting the references entries for `path'. */
{ pathInfoCache->lock()->erase(std::string(path.to_string()));
auto state_(Store::state.lock());
state_->pathInfoCache.erase(std::string(path.to_string()));
}
} }
const PublicKeys & LocalStore::getPublicKeys() const PublicKeys & LocalStore::getPublicKeys()

View file

@ -764,10 +764,7 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
results.bytesFreed = readLongLong(conn->from); results.bytesFreed = readLongLong(conn->from);
readLongLong(conn->from); // obsolete readLongLong(conn->from); // obsolete
{ pathInfoCache->lock()->clear();
auto state_(Store::state.lock());
state_->pathInfoCache.clear();
}
} }
void RemoteStore::optimiseStore() void RemoteStore::optimiseStore()

View file

@ -306,7 +306,7 @@ StringSet Store::Config::getDefaultSystemFeatures()
Store::Store(const Store::Config & config) Store::Store(const Store::Config & config)
: StoreDirConfig{config} : StoreDirConfig{config}
, config{config} , config{config}
, state({(size_t) config.pathInfoCacheSize}) , pathInfoCache(make_ref<decltype(pathInfoCache)::element_type>((size_t) config.pathInfoCacheSize))
{ {
assertLibStoreInitialized(); assertLibStoreInitialized();
} }
@ -326,7 +326,7 @@ bool Store::PathInfoCacheValue::isKnownNow()
void Store::invalidatePathInfoCacheFor(const StorePath & path) void Store::invalidatePathInfoCacheFor(const StorePath & path)
{ {
state.lock()->pathInfoCache.erase(path.to_string()); pathInfoCache->lock()->erase(path.to_string());
} }
std::map<std::string, std::optional<StorePath>> Store::queryStaticPartialDerivationOutputMap(const StorePath & path) std::map<std::string, std::optional<StorePath>> Store::queryStaticPartialDerivationOutputMap(const StorePath & path)
@ -448,22 +448,18 @@ void Store::querySubstitutablePathInfos(const StorePathCAMap & paths, Substituta
bool Store::isValidPath(const StorePath & storePath) bool Store::isValidPath(const StorePath & storePath)
{ {
{ auto res = pathInfoCache->lock()->get(storePath.to_string());
auto state_(state.lock());
auto res = state_->pathInfoCache.get(storePath.to_string());
if (res && res->isKnownNow()) { if (res && res->isKnownNow()) {
stats.narInfoReadAverted++; stats.narInfoReadAverted++;
return res->didExist(); return res->didExist();
} }
}
if (diskCache) { if (diskCache) {
auto res = diskCache->lookupNarInfo( auto res = diskCache->lookupNarInfo(
config.getReference().render(/*FIXME withParams=*/false), std::string(storePath.hashPart())); config.getReference().render(/*FIXME withParams=*/false), std::string(storePath.hashPart()));
if (res.first != NarInfoDiskCache::oUnknown) { if (res.first != NarInfoDiskCache::oUnknown) {
stats.narInfoReadAverted++; stats.narInfoReadAverted++;
auto state_(state.lock()); pathInfoCache->lock()->upsert(
state_->pathInfoCache.upsert(
storePath.to_string(), storePath.to_string(),
res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{} res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{}
: PathInfoCacheValue{.value = res.second}); : PathInfoCacheValue{.value = res.second});
@ -518,8 +514,7 @@ std::optional<std::shared_ptr<const ValidPathInfo>> Store::queryPathInfoFromClie
{ {
auto hashPart = std::string(storePath.hashPart()); auto hashPart = std::string(storePath.hashPart());
{ auto res = pathInfoCache->lock()->get(storePath.to_string());
auto res = state.lock()->pathInfoCache.get(storePath.to_string());
if (res && res->isKnownNow()) { if (res && res->isKnownNow()) {
stats.narInfoReadAverted++; stats.narInfoReadAverted++;
if (res->didExist()) if (res->didExist())
@ -527,21 +522,17 @@ std::optional<std::shared_ptr<const ValidPathInfo>> Store::queryPathInfoFromClie
else else
return std::make_optional(nullptr); return std::make_optional(nullptr);
} }
}
if (diskCache) { if (diskCache) {
auto res = diskCache->lookupNarInfo(config.getReference().render(/*FIXME withParams=*/false), hashPart); auto res = diskCache->lookupNarInfo(config.getReference().render(/*FIXME withParams=*/false), hashPart);
if (res.first != NarInfoDiskCache::oUnknown) { if (res.first != NarInfoDiskCache::oUnknown) {
stats.narInfoReadAverted++; stats.narInfoReadAverted++;
{ pathInfoCache->lock()->upsert(
auto state_(state.lock());
state_->pathInfoCache.upsert(
storePath.to_string(), storePath.to_string(),
res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{} res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{}
: PathInfoCacheValue{.value = res.second}); : PathInfoCacheValue{.value = res.second});
if (res.first == NarInfoDiskCache::oInvalid || !goodStorePath(storePath, res.second->path)) if (res.first == NarInfoDiskCache::oInvalid || !goodStorePath(storePath, res.second->path))
return std::make_optional(nullptr); return std::make_optional(nullptr);
}
assert(res.second); assert(res.second);
return std::make_optional(res.second); return std::make_optional(res.second);
} }
@ -577,10 +568,7 @@ void Store::queryPathInfo(const StorePath & storePath, Callback<ref<const ValidP
if (diskCache) if (diskCache)
diskCache->upsertNarInfo(config.getReference().render(/*FIXME withParams=*/false), hashPart, info); diskCache->upsertNarInfo(config.getReference().render(/*FIXME withParams=*/false), hashPart, info);
{ pathInfoCache->lock()->upsert(storePath.to_string(), PathInfoCacheValue{.value = info});
auto state_(state.lock());
state_->pathInfoCache.upsert(storePath.to_string(), PathInfoCacheValue{.value = info});
}
if (!info || !goodStorePath(storePath, info->path)) { if (!info || !goodStorePath(storePath, info->path)) {
stats.narInfoMissing++; stats.narInfoMissing++;
@ -803,10 +791,7 @@ StorePathSet Store::exportReferences(const StorePathSet & storePaths, const Stor
const Store::Stats & Store::getStats() const Store::Stats & Store::getStats()
{ {
{ stats.pathInfoCacheSize = pathInfoCache->readLock()->size();
auto state_(state.readLock());
stats.pathInfoCacheSize = state_->pathInfoCache.size();
}
return stats; return stats;
} }

View file

@ -18,6 +18,9 @@ private:
std::shared_ptr<T> p; std::shared_ptr<T> p;
public: public:
using element_type = T;
explicit ref(const std::shared_ptr<T> & p) explicit ref(const std::shared_ptr<T> & p)
: p(p) : p(p)
{ {

View file

@ -36,6 +36,8 @@ private:
public: public:
using element_type = T;
SyncBase() {} SyncBase() {}
SyncBase(const T & data) SyncBase(const T & data)