Skip to content

Perf: helper-runtime cache key is too coarse — one lowering edit invalidates all 257 units #23458

Description

@PurHur

prelinked/helper-runtime/x86_64-linux/manifest.json is keyed on a single core_fingerprint covering the whole lowering machinery — lib/JIT.php, lib/Runtime.php, lib/JIT/Context.php, lib/JIT/JitVmHelperLink.php, composer.lock, plus the patches digest. Any change to any of those invalidates every committed unit at once, and a cold phpc build re-emits the entire ~257-unit corpus live.

Why this matters more than it looks

master touches at least one of those files most days. Measured on this repo, the committed fingerprint had not moved since 2026-07-06 while master's computed value had moved repeatedly — 20 days during which every cold build paid full corpus emission. Compiling this:

<?php echo "hello ", 1 + 2, "\n";

pinned 13 cores emitting helper units. After #23457 refreshed the cache, the same build reports helper-runtime cache hit and takes 5.1 s.

So the cache works — it just spends most of its life switched off. Refreshing it (#23457) buys days, not weeks.

The structural shape

This is the same failure mode as the gen-0 stamp (#22642): a committed artifact keyed on a fingerprint that changes several times a day, so it is stale far more often than fresh, and "refresh it" is a treadmill rather than a fix.

Suggested direction

Key each unit on what that unit actually depends on, rather than on a global fingerprint:

  • per-unit source sha (the helper file itself) + the transitive set of lowerings it actually reached during emission — the emitter already knows this closure, since markEmitting()/JitVmHelperLink walk it;
  • keep a coarse fingerprint only for genuinely global inputs (patches digest, composer.lock, LLVM version);
  • then an edit to one lowering invalidates the units that reached it, not the corpus.

The per-unit manifests already exist (units/*/manifest.json), so the storage shape is mostly there — what is missing is recording the dependency closure at emit time and checking it per unit instead of checking one global value.

Done when: editing a single helper or a single lowering invalidates a bounded subset of units, demonstrated by a cold build after such an edit re-emitting that subset rather than ~257 units.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions