mirror of
https://github.com/NixOS/nix.git
synced 2025-11-09 03:56: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:
parent
5ae1b5f88b
commit
a73cf447ac
7 changed files with 37 additions and 63 deletions
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
using element_type = T;
|
||||||
|
|
||||||
SyncBase() {}
|
SyncBase() {}
|
||||||
|
|
||||||
SyncBase(const T & data)
|
SyncBase(const T & data)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue