Skip to content

perf(libc): avoid repeated Windows path component scans - #7467

Merged
oneandonlydean merged 4 commits into
boykopovar:mainfrom
Dripl1x:codex/windows-path-component-lookup
Oct 21, 2026
Merged

oneandonlydean merged 4 commits into
boykopovar:mainfrom
Dripl1x:codex/windows-path-component-lookup

Conversation

@Dripl1x

@Dripl1x Dripl1x commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

What

Avoid repeated case-insensitive directory scans while resolving Windows guest paths. Use FindFirstFileExW only when the directory explicitly reports case-insensitive behaviour, return existing non-reparse paths directly, and start component matching at the longest existing ancestor. Preserve enumeration for case-sensitive directories and failed or unsupported attribute queries.

Tested

Rebased onto main e1dae23e01a412571c2575fe794475b4c0e7adf9; source head 5a1590c9f8eefc50d7080f26fae3b8ed07ff99bc. Merge compatibility was also checked against later main 5057673804b28d217559010d7ac1f702824f240b. Thanks to @blawesom for porting the prefix walk to main's split-name ResolveHostPath interface and reporting Linux coverage.

The port initially advanced first to last after selecting the existing parent, skipping the final component. The Windows guest_filesystem test reproduced the failure at parent traversal before the fix. Changing the iterator to std::prev(last) preserves the final component; rebuilding and rerunning the same test passes. The regression coverage for mixed-case file/directory lookup, relinked module names and ambiguous Both/both names on NTFS case-sensitive directories is retained and passes. The libc runtime was rebuilt from the corrected source. @blawesom's Linux results in the review are credited as their validation, not a fresh local full-suite run.

SuperTuxKart captures for the bot's before/after requirement: Windows 11 Pro build 26300, Ryzen 7 5800H, RTX 3070 Laptop GPU, NVIDIA 617.42, WinLibs GCC 15.2.0 r7, Release; SuperTuxKart (PPSA69421) tutorial prompt over the main menu, 1920x1080 internal rendering in a maximized 2560x1369 window, warm shader caches, audio muted, no input; APS5_TRACE_SECONDS=20:8 with APS5_TRACE_EVENTS=1048576, console output not redirected, no profiling switches; 2026-10-21, A-B-B-A, order main, PR, PR, main.

Capture Build Commit FPS p50 / p90 / p99 ms
rv21-t01-main-e1 main e1dae23e01a4 e1dae23e01a4 9.458 105.7 / 107.9 / 110.8
rv21-t04-main-e1 main e1dae23e01a4 e1dae23e01a4 9.311 106.0 / 112.1 / 115.3
rv21-t02-7467 this PR 5a1590c9f8ee 9.450 104.7 / 108.0 / 123.2
rv21-t03-7467 this PR 5a1590c9f8ee 9.404 105.8 / 109.7 / 118.4

The FPS difference is within the run-to-run spread of main; this PR claims no FPS change. What it saves is shown under Where it helps.

Summary lines (main first, then this PR)
{"commit":"e1dae23e01a4","dirty":false,"env":{"APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":37,"ms":8035.601},"presents":76,"frame_ms":{"p50":105.687,"p90":107.866,"p99":110.766,"max":110.766},"gpu_busy_ms_per_present":5.418,"worker_busy_pct":{"queue worker 0x0":2.921},"top_phases_ms_per_frame":{"Driver.Packet":3.040,"Driver.Packet.draw":2.452,"Driver.Draw":2.383,"Driver.Draw.shader_compile_and_link":1.380,"VideoOut.Flip":0.975,"Driver.Present":0.881,"VideoOut.Flip.present":0.867,"Shader.DrawStage":0.688},"trace_dropped":false,"trace":"aps5-trace-e1dae23e01a4-46916.json.gz"}
{"commit":"e1dae23e01a4","dirty":false,"env":{"APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":35,"ms":8054.635},"presents":75,"frame_ms":{"p50":105.981,"p90":112.071,"p99":115.274,"max":115.274},"gpu_busy_ms_per_present":5.406,"worker_busy_pct":{"queue worker 0x0":3.188},"top_phases_ms_per_frame":{"Driver.Packet":3.371,"Driver.Packet.draw":2.739,"Driver.Draw":2.674,"Driver.Draw.shader_compile_and_link":1.585,"VideoOut.Flip":0.985,"Driver.Present":0.877,"VideoOut.Flip.present":0.865,"Shader.DrawStage":0.808},"trace_dropped":false,"trace":"aps5-trace-e1dae23e01a4-48816.json.gz"}
{"commit":"5a1590c9f8ee","dirty":false,"env":{"APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":67,"ms":8042.332},"presents":76,"frame_ms":{"p50":104.714,"p90":107.963,"p99":123.174,"max":123.174},"gpu_busy_ms_per_present":5.423,"worker_busy_pct":{"queue worker 0x0":2.975},"top_phases_ms_per_frame":{"Driver.Packet":3.103,"Driver.Packet.draw":2.478,"Driver.Draw":2.419,"Driver.Draw.shader_compile_and_link":1.383,"VideoOut.Flip":0.966,"Driver.Present":0.869,"VideoOut.Flip.present":0.856,"Shader.DrawStage":0.699},"trace_dropped":false,"trace":"aps5-trace-5a1590c9f8ee-31600.json.gz"}
{"commit":"5a1590c9f8ee","dirty":false,"env":{"APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":64,"ms":8081.557},"presents":76,"frame_ms":{"p50":105.769,"p90":109.726,"p99":118.382,"max":118.382},"gpu_busy_ms_per_present":5.481,"worker_busy_pct":{"queue worker 0x0":3.024},"top_phases_ms_per_frame":{"Driver.Packet":3.169,"Driver.Packet.draw":2.576,"Driver.Draw":2.504,"Driver.Draw.shader_compile_and_link":1.447,"VideoOut.Flip":0.984,"Driver.Present":0.876,"VideoOut.Flip.present":0.865,"Shader.DrawStage":0.730},"trace_dropped":false,"trace":"aps5-trace-5a1590c9f8ee-50844.json.gz"}
tools/performance_compare.py (first capture of each side)

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline e1dae23 aps5-trace-e1dae23e01a4-46916.json.gz 76 8035.601
candidate 5a1590c aps5-trace-5a1590c9f8ee-31600.json.gz 76 8042.332
  • Compare captures from the same machine, title and scene; summaries do not record the CPU, title or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.

Configuration differences

Setting Baseline Candidate
window.first_present 37 67

Frame and GPU times (ms)

Metric Baseline Candidate Change Change (%)
frame_ms.p50 105.687 104.714 -0.973 -0.921
frame_ms.p90 107.866 107.963 +0.097 +0.090
frame_ms.p99 110.766 123.174 +12.408 +11.202
frame_ms.max 110.766 123.174 +12.408 +11.202
mean_frame_ms 105.732 105.820 +0.089 +0.084
gpu_busy_ms_per_present 5.418 5.423 +0.005 +0.092

Top phases (ms per frame)

Metric Baseline Candidate Change Change (%)
Driver.Draw 2.383 2.419 +0.036 +1.511
Driver.Draw.shader_compile_and_link 1.380 1.383 +0.003 +0.217
Driver.Packet 3.040 3.103 +0.063 +2.072
Driver.Packet.draw 2.452 2.478 +0.026 +1.060
Driver.Present 0.881 0.869 -0.012 -1.362
Shader.DrawStage 0.688 0.699 +0.011 +1.599
VideoOut.Flip 0.975 0.966 -0.009 -0.923
VideoOut.Flip.present 0.867 0.856 -0.011 -1.269
tools/trace_digest.py output (first capture of each side; all digests are in the evidence archive)

rv21-t01-main-e1

seconds 20:8 from present 37: 76 presents, frame p50 105.7 / p90 107.9 / p99 110.8 / max 110.8 ms, GPU busy 5.4 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit e1dae23, dropped: no

{"commit":"e1dae23e01a4","dirty":false,"env":{"APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":37,"ms":8035.601},"presents":76,"frame_ms":{"p50":105.687,"p90":107.866,"p99":110.766,"max":110.766},"gpu_busy_ms_per_present":5.418,"worker_busy_pct":{"queue worker 0x0":2.921},"top_phases_ms_per_frame":{"Driver.Packet":3.04,"Driver.Packet.draw":2.452,"Driver.Draw":2.383,"Driver.Draw.shader_compile_and_link":1.38,"VideoOut.Flip":0.975,"Driver.Present":0.881,"VideoOut.Flip.present":0.867,"Shader.DrawStage":0.688},"trace_dropped":false,"trace":"aps5-trace-e1dae23e01a4-46916.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 112: 110.8 ms at 7925 ms: Driver.WorkerWait (queue worker 0x0) 106.8, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 106.7, batch (gpu) 5.4, Driver.Packet (queue worker 0x0) 2.9
  • present 70: 110.4 ms at 3472 ms: Driver.WorkerWait (queue worker 0x0) 106.7, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 106.6, batch (gpu) 5.4, Driver.Packet (queue worker 0x0) 2.6
  • present 93: 109.7 ms at 5924 ms: Driver.WorkerWait (queue worker 0x0) 105.9, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 105.8, batch (gpu) 5.4, Driver.Packet (queue worker 0x0) 2.7

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
title 0.0 (0 %) 0.0 (0 %) 105.7 0.4 Recorder.Sync 0.0
queue worker 0x0 2.5 (2 %) 102.3 (97 %) 1.0 3.6 Driver.Packet 2.5, Driver.EndSubmission 0.0
presenter 1.0 (1 %) 0.0 (0 %) 104.7 0.1 VideoOut.Flip 1.0, Driver.Present 0.0
gpu 5.4 (5 %) 0.0 (0 %) 100.3 0.0 batch 5.4

rv21-t02-7467

seconds 20:8 from present 67: 76 presents, frame p50 104.7 / p90 108.0 / p99 123.2 / max 123.2 ms, GPU busy 5.4 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit 5a1590c, dropped: no

{"commit":"5a1590c9f8ee","dirty":false,"env":{"APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":67,"ms":8042.332},"presents":76,"frame_ms":{"p50":104.714,"p90":107.963,"p99":123.174,"max":123.174},"gpu_busy_ms_per_present":5.423,"worker_busy_pct":{"queue worker 0x0":2.975},"top_phases_ms_per_frame":{"Driver.Packet":3.103,"Driver.Packet.draw":2.478,"Driver.Draw":2.419,"Driver.Draw.shader_compile_and_link":1.383,"VideoOut.Flip":0.966,"Driver.Present":0.869,"VideoOut.Flip.present":0.856,"Shader.DrawStage":0.699},"trace_dropped":false,"trace":"aps5-trace-5a1590c9f8ee-31600.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 83: 123.2 ms at 1684 ms: Driver.WorkerWait (queue worker 0x0) 118.1, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 118.0, batch (gpu) 5.4, Driver.Packet (queue worker 0x0) 3.7
  • present 84: 121.2 ms at 1808 ms: Driver.WorkerWait (queue worker 0x0) 116.3, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 116.0, batch (gpu) 5.4, Driver.Packet (queue worker 0x0) 3.7
  • present 82: 117.2 ms at 1567 ms: Driver.WorkerWait (queue worker 0x0) 112.8, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 112.7, batch (gpu) 5.4, Driver.Packet (queue worker 0x0) 3.2

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
title 0.0 (0 %) 0.0 (0 %) 105.8 0.4 Recorder.Sync 0.0
queue worker 0x0 2.5 (2 %) 102.3 (97 %) 1.0 3.7 Driver.Packet 2.5, Driver.EndSubmission 0.0
presenter 1.0 (1 %) 0.0 (0 %) 104.8 0.1 VideoOut.Flip 1.0, Driver.Present 0.0
gpu 5.4 (5 %) 0.0 (0 %) 100.4 0.0 batch 5.4

The earlier seven filesystem cases and UI Lab/homebrew navigation evidence predate this rebase. No startup-duration improvement is claimed. vkQuake's known baseline flicker/black-floor issue remains outside this change.

Where it helps

Path resolution happens mostly while the title starts and loads. Over the whole run the call counts are identical on both sides, so totals compare directly (CPU time summed over the calling threads, not wall-clock startup time):

Function Calls over the run, main / series Total time, main / series
ResolveHostPath 11,928 / 11,928 9.25 s / 5.46 s
MatchNames 7,460 / 7,460 4.72 s / 1.93 s

Counters come from a local probe build that is not part of this PR (review-probe.patch in the evidence archive): the same counters and timers were inserted into main 2185dbf92e and into main with all eleven series PRs merged (#7464 in its rebased form), anchored on function definitions present in both trees. Runs were in the mirrored order main, series with #7464 reduced to its wake only, series, series, reduced series, main, in the scene above with APS5_PROFILE_DRAW=1; values are medians of two runs over the same 8-second window as the trace, starting 20 s after the first flip, per flip. These runs carry profiling overhead and are not used for FPS. Each optimised function below is changed by this PR only; counters show where the work goes, not an isolated FPS gain.

Dependencies and overlap

No required PR dependency. Main's current vector-based path interface is preserved. The earlier review correction for case-sensitive directories remains in place; #6061 and #6226 were previously identified as related path-resolution overlaps and are not claimed as this implementation.

Re-checked on 2026-10-21: this head still merges cleanly into main 2185dbf92e. #6658, which the earlier combined runs carried, merged into main on 2026-10-20.

Checklist

  • One topic per PR; existing main-checkout work was preserved
  • No comments in code except technical debt
  • Unimplemented paths throw; no new silent stubs
  • No investigation files or images added to the repository
  • No new third-party code
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA RTX 3070 Laptop, NVIDIA 617.42, Windows 11 Pro build 26300
  • AI-assisted: yes

Reproduction evidence

Windows negative-control/fixed test logs, source provenance, frozen runtime manifests and completed/incomplete game-run records. Earlier series evidence is historical and tied to its original revisions. Current hosted checks are shown in the PR checks; no full-suite result is inferred from metadata checks.

Update of 2026-10-21: 7467-evidence.zip (traces, summary lines, trace_digest.py and performance_compare.py output, loaded-module hashes), counters where.json and the probe review-probe.patch with probe_window.py.

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 8626 core/libs/prx/libc/src/General.cpp L88-89

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 5021 core/libs/prx/libc/src/General.cpp
PR 6044 core/libs/tests/GuestFilesystem.cpp
PR 6226 core/libs/prx/libc/src/General.cpp
PR 6879 core/libs/prx/libc/src/General.cpp
PR 7201 core/libs/prx/libc/src/General.cpp
PR 7530 core/libs/tests/GuestFilesystem.cpp
PR 8550 core/libs/tests/GuestFilesystem.cpp
PR 8658 core/libs/prx/libc/src/General.cpp

@github-actions github-actions Bot added the libc label Oct 18, 2026
@wachi35676

Copy link
Copy Markdown
Contributor

I ran a differential test of the old and new MatchNames/ResolveHostPath bodies, compiled together into one harness (Windows 11 26300, Ryzen 5 9600X, WinLibs GCC 15.2.0, Release, PR merged onto main 9f25d0bf5). It ran 40,000 random paths over a tree containing a normal directory, a junction, a dangling symlink, .., . and trailing slashes. The results are identical except inside a directory with the per-directory case-sensitive attribute (fsutil file setCaseSensitiveInfo <dir> enable). There, 759 of the 40,000 results differ.

In this example, directory Sens contains File.txt, Sub/, and both Both and both:

input main this PR
Sens/file.txt Sens/File.txt Sens/file.txt (does not exist)
Sens/sub Sens/Sub Sens/sub (does not exist)
sens/BOTH/FILE.TXT throws "Ambiguous case-insensitive guest path" sens/BOTH/FILE.TXT (does not exist)

The cause: inside a case-sensitive directory, FindFirstFileExW(dir\file.txt) returns ERROR_FILE_NOT_FOUND even without FIND_FIRST_EX_CASE_SENSITIVE. The old directory_iterator + SameName scan finds File.txt. On NTFS this is the main case where the fallback matters at all, since GetFileAttributesW already matches case-insensitively in ordinary directories.

Either of these would keep the old behaviour:

  • fall back to the enumeration when the directory is case-sensitive (FILE_CASE_SENSITIVE_INFORMATION via GetFileInformationByHandleEx);
  • use the pattern lookup only for the existing-prefix shortcut.

The speedup is real for misses: a missing name in a 3,000-entry directory takes 14.8–17.3 ms on main and 0.26 ms with this PR. Existing paths are unchanged at about 30–50 µs. The 462-test set (guest_, libkernel, libc and related) passes on main and with this PR.

AI-assisted: yes (Claude Code); results above were run on this machine.

@Dripl1x

Dripl1x commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

@wachi35676 Thanks for the differential test and the case-sensitive directory reproducer. Fixed in feed2ea53c00: the pattern lookup is now used only when the directory explicitly reports case-insensitive behaviour; case-sensitive directories and failed/unsupported attribute queries use the original enumeration. The new guest filesystem regression covers mixed-case file/directory lookup, relinked module names and ambiguous Both/both names on an NTFS case-sensitive directory. It fails with the previous implementation and passes with the correction.

The three corrections (#7467, #7469 and #7470) were also checked together against the previous series in a same-scene SuperTuxKart A-B-B-A repeat: 32.680 -> 32.722 FPS (1920x1080 internal rendering, maximized 2560x1369 client, warm caches, trace seconds 20-28, RTX 3070 Laptop/NVIDIA 617.42). Focus and loaded-module hashes were verified. This combined check does not assign a separate FPS gain to this PR. #7473 is being validated separately.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
@blawesom

Copy link
Copy Markdown
Contributor

Rebase handoff, with a port onto main's reworked signature — main changed ResolveHostPath to take split name vectors with Child()/JoinNames() helpers while this PR's scan-avoidance was written against the std::filesystem::path form. The merged version keeps main's structure and ports your Windows prefix walk onto it: the reparse-point scan walks the vector prefixes (longest existing non-reparse parent first) and advances the first iterator into the vector, so the component loop starts where the scans left off — the same single-scan behaviour, on main's shape. Worth a review of that hunk since it is a port, not a transcription.

Verified on Linux (CachyOS, kernel 7.2.9, GCC 16.2.1, Ninja, Release, BUILD_TESTING=ON, AMD RX 9070 XT / RADV): builds; conventions pass; the path/filesystem tests pass; full suite green apart from the two known main regressions (agc_driver_tessellation — Mesa, #5444; agc_driver_bda_device — #7584), neither from this PR (your Windows prefix walk is _WIN32-gated).

To pick it up:

git fetch https://github.com/blawesom/AnyPS5 rebase/7467
git checkout <your branch>
git merge --ff-only FETCH_HEAD

Head is 4703ca7e0.

@Dripl1x
Dripl1x force-pushed the codex/windows-path-component-lookup branch from feed2ea to 5a1590c Compare October 18, 2026 18:28
@Dripl1x

Dripl1x commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for porting this to main's split-name interface and for the Linux validation. Picked up the handoff and rebased onto main e1dae23. Windows validation caught one iterator error in the port: after selecting the existing parent, first = last skipped the final path component. Changed it to first = std::prev(last). The existing guest_filesystem parent-traversal case fails before this correction and passes after rebuilding with it; the earlier case-sensitive NTFS and relinked-module regression coverage is retained. Published head: 5a1590c. The PR description distinguishes the completed filesystem checks from the incomplete game repeat. Negative-control and fixed-run logs, source provenance and runtime manifests: https://github.com/Dripl1x/AnyPS5/releases/download/performance-series-20261018/review-rebase-20261018.zip

@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line and removed needs rebase Conflicts with main, rebase needed labels Oct 18, 2026
@github-actions

Copy link
Copy Markdown

This pull request is labeled perf, so it needs the summary line of a capture on main and one with the change, from the same title, scene and machine, as the Performance report form asks. Please paste both aps5-summary.jsonl lines, attach the two traces and add the output of tools/trace_digest.py.

@wachi35676

Copy link
Copy Markdown
Contributor

Re-checked 5a1590c9f merged onto main 07377573f (Windows 11 26300, GCC 15.2).

  • Differential test: I compiled the old and new ResolveHostPath bodies into one harness. They give 0 differences over 40,006 paths, on a tree with a case-sensitive directory, a junction, a dangling symlink, trailing slashes and module relinking. Spot checks:

    • Sens/file.txt → Sens/File.txt
    • sens/deep/in/LEAF.bin → sens/Deep/In/Leaf.bin
    • Sens/BOTH still raises the ambiguity error.

    The only remaining differences need a .. component, which Resolve() removes before calling ResolveHostPath.

  • Prefix walk: the std::prev(last) walk handles empty, single-component, none-existing, all-existing and reparse-in-the-middle paths exactly as main does.

  • New test: TestCaseSensitiveHostDirectory passes. With MatchNames forced back to the FindFirstFileExW lookup, it fails with 0xc0000409.

  • Speed: a miss in a 3,000-entry directory still goes from about 31 ms to about 0.3 ms. Case-sensitive directories keep main's cost.

  • Regression set: the 472-test set passes. guest_select and guest_select_wait flaked under -j4 and pass when run serially.

AI-assisted: yes (Claude Code); results above were run on this machine.

@oneandonlydean oneandonlydean self-assigned this Oct 20, 2026
@github-actions github-actions Bot removed the perf numbers missing perf pull request without a before and after summary line label Oct 20, 2026
@Dripl1x

Dripl1x commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Updated the description: before/after summary lines from the same machine and SuperTuxKart scene (main e1dae23e01a4 9.46 / 9.31 FPS, this PR 5a1590c9f8ee 9.45 / 9.40 FPS, so no FPS claim), trace_digest.py and performance_compare.py output, and probe counters that show where this change saves work in that scene: at identical call counts over the run (11,928 ResolveHostPath, 7,460 MatchNames, mostly while the title starts), path resolution takes 9.25 s on main and 5.46 s with this PR, and MatchNames 4.72 s against 1.93 s (CPU time summed over threads, not wall-clock startup). Traces, digests and the probe patch are in the evidence release. The head is unchanged and still merges cleanly into current main.

AI-assisted: yes (Claude Code)

@oneandonlydean
oneandonlydean merged commit 46c7538 into boykopovar:main Oct 21, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants