Skip to content

fix(build): the hash record is written under its build's start, and keeps only the keys used - #2873

Open
jordanella wants to merge 1 commit into
NotRexed:mainfrom
jordanella:fix/hash-cache-clock
Open

jordanella wants to merge 1 commit into
NotRexed:mainfrom
jordanella:fix/hash-cache-clock

Conversation

@jordanella

@jordanella jordanella commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

hckrman101's two non-blocking points on #2702: the hash record was written under the time it was saved, seconds after the sources were stat'd, which loosens the 2 s rule on coarse-timestamp filesystems; and the record only grew, one key per renderer source for every header edit.

Change

nx2/build.py:

  • The record's time is its build's start: load_hashes takes the time before any source is stat'd (HASHES_STARTED), and save_hashes writes that as written_ns, not the time of the save after the whole plan.
  • Only the keys used are kept: key_of and content_sha1 note what this build asked for, per source (USED). For each source this build looked at, the record keeps only those keys. A source it didn't look at, such as a renderer-only build's lifted C, keeps its record as it was.

Nothing about the keys themselves changes, so no object is renamed and nothing compiles again for this change.

Measured

Windows 11, Ryzen 9 3900X, a work folder of 874 sources. Each column is a build: a comment added to gpu/vk/vk_present_rect.h, a second comment, both taken out again, then a build with nothing changed. The numbers are the record's total keys after each build.

build.py start 1st edit 2nd edit reverted no change
main (#2702) 897 932 967 967 967
this branch 897 897 897 897 897

The record stays at one key per source per flag set, at most 3 on one source in both. On this branch the two edits compiled 2 files each, not 35, because main's run had already cached objects for the same header contents.

In the game

The game from this branch's last build, launched headless through the control bridge from a save (RTX 3080, NVIDIA 621.14, Windows 11): in play in Kokiri Forest, 27–32 fps over five samples, nothing in the log about a lost device or a crash. The change is build-only and shows nothing on screen.

Testing

  • tests/test_build_hash_cache.py, two new cases:

    • the record's time is the load's, not the save's;
    • a source looked at keeps only its used keys, and one not looked at keeps all of its.

    Both fail on main.

  • Every check that reads the changed files (35), through run_all.py on Windows with the Builder's Python and clang, rebased on today's main: 31 pass; four fail the same way on main here: test_driver_cache_folder, test_fpx_sticky, test_linux_update and nx2/test_dll.py (it needs a DLL build).

  • Not tested: Linux. Nothing here is platform-specific; the record's id is the inode there.

See #2702, #2636 (A5).

🤖 Generated with Claude Code

…eeps only the keys used

hckrman101's two points on NotRexed#2702. The record was written under the time of its save, after the whole plan, seconds after
each source was stat'd; the 2 s "racily clean" rule is about the stat, so it is written under the time load_hashes ran,
before any. And it only grew: each header edit added a key to every renderer source. Each source this build looked at
now keeps only the keys this build asked for (key_of, content_sha1); a source it did not look at, such as a
renderer-only build's lifted C, keeps its record as it was.

tests/test_build_hash_cache.py: the record's time is the load's, and a source looked at keeps only its used keys while
one not looked at keeps all of its (both fail on main).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant