[Kernel] Remember APR paths absent from the read-only game image

Looking up a resolved path's size stats the host filesystem, and a path that
is not there costs two stats (a file probe and a directory probe) every single
time it is asked for. A resource streamer asks for far more paths than the
image contains, so misses are the common case and they are repeated.

/app0 is the read-only game image: a path that is not in it now will not
appear later. Absent paths under that root are therefore remembered, which
turns the repeated pair of host stats on what is often a slow external volume
into a dictionary probe. Paths outside /app0 can be created at run time and
are not remembered.
This commit is contained in:
kuba 2026-09-29 23:58:28 +02:00
parent 7a42dbbf14
commit 66304399ae
1 changed files with 23 additions and 0 deletions

View File

@ -6883,6 +6883,19 @@ public static partial class KernelMemoryCompatExports
return TryWriteHostPathStat(ctx, statAddress, hostPath, isDirectory);
}
// /app0 is the read-only game image, so a path that is not in it now will not
// appear later. Remembering the absent ones turns a repeated pair of host stats
// on the (slow, external) game volume into a dictionary probe; Demon's Souls
// resolves tens of thousands of paths per boot and misses are the common case.
private static readonly ConcurrentDictionary<string, byte> _aprMissingImagePaths = new(HostFsPath.Comparer);
private static bool IsUnderApp0(string cachePath)
{
var app0Root = ResolveApp0Root();
return !string.IsNullOrWhiteSpace(app0Root) &&
cachePath.StartsWith(Path.TrimEndingDirectorySeparator(app0Root) + Path.DirectorySeparatorChar, HostFsPath.Comparison);
}
private static bool TryGetAprFileSize(string hostPath, out ulong size)
{
size = 0;
@ -6902,6 +6915,11 @@ public static partial class KernelMemoryCompatExports
return true;
}
if (_aprMissingImagePaths.ContainsKey(cachePath))
{
return false;
}
// One directory listing returns every file's size; titles resolve whole asset
// directories at startup, so this replaces one host query per file.
if (Path.GetDirectoryName(cachePath) is { } directory && _aprScannedDirectories.TryAdd(directory, 0))
@ -6936,6 +6954,11 @@ public static partial class KernelMemoryCompatExports
if (!new DirectoryInfo(cachePath).Exists)
{
if (IsUnderApp0(cachePath))
{
_aprMissingImagePaths.TryAdd(cachePath, 0);
}
return false;
}