Repository navigation
Conversation
The entry names #9194. Signed-off-by: Jono Prest <jjprest@gmail.com>
|
@codex review |
Changelog💅 Polish
Semantic Diff1 commit · Full page Copy a dependency's values when they are read94bd206 · JonoPrest · Nov 03, 2026, 11:26 UTC
For the components of a .cmi signature as it was read, values are now table cells that make the copy on first read. Type ids are allocated in order and end up in .cmt files and in which nodes the backtracking trail logs, so the copies keep their ids: once the process has built the components of the same .cmi contents (same CRC) eagerly, it knows how many type ids each value takes, reserves them when the components are built and makes the copy with exactly those ids when the value is read. A copy that takes a different number is made again with fresh ids, like the deferred signature copies, and counted per domain for the tests. One-shot bsc and the first use of an interface in a build still build eagerly. Types, constructors, labels, extension constructors, module types, submodules and components of anything else (aliases, functor applications, local modules) are built as before. The tables of an open take the cells too: an open keeps a function giving the binding of each component, and the bindings Env.copy_types replaces through an open in a table checked before the components. Review
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## jono/defer-signature-copy #9194 +/- ##
=============================================================
+ Coverage 81.76% 81.84% +0.07%
=============================================================
Files 459 460 +1
Lines 65448 65793 +345
=============================================================
+ Hits 53516 53846 +330
- Misses 11932 11947 +15
🚀 New features to boost your workflow:
|
rescript
@rescript/belt
@rescript/darwin-arm64
@rescript/linux-arm64
@rescript/linux-x64
@rescript/runtime
@rescript/win32-x64
commit: |
8810538 to
67eb3bc
Compare
Why:
Forcing a dependency's components copied every value of its interface
with the module path substitution, although a dependent reads only a
few of them: on a 552-module app, about 5 % of the values of .cmi
components are ever read.
For the components of a .cmi signature as it was read, values are now
table cells that make the copy on first read. Type ids are allocated in
order and end up in .cmt files and in which nodes the backtracking trail
logs, so the copies keep their ids: once the process has built the
components of the same .cmi contents (same CRC) eagerly, it knows how many
type ids each value takes, reserves them when the components are built and
makes the copy with exactly those ids when the value is read. A copy that
takes a different number is made again with fresh ids, like the deferred
signature copies, and counted per domain for the tests. One-shot bsc and
the first use of an interface in a build still build eagerly. Types,
constructors, labels, extension constructors, module types, submodules and
components of anything else (aliases, functor applications, local modules)
are built as before.
The tables of an open take the cells too: an open keeps a function giving
the binding of each component, and the bindings Env.copy_types replaces
through an open in a table checked before the components.
Review: Can a deferred copy differ from the eager one apart from when it is
made? The copied values are the unmarshalled .cmi signature, which the type
checker never sees (it only gets copies), and the copy takes no stamps; the
type ids are the eager ones, so every later stamp and id, and every
operation on the copied nodes, is the same. The new unit tests compare
marshalled results of eager and deferred components over every runtime
interface, and whole requests (outputs, .cmt and error messages) using
functors, aliases, include, module type of, recursive modules, shadowing
and first-class modules, also on several domains at once.
Review: Are the cells shared between requests or domains? No: components
belong to the persistent structures of one request; only the count table is
shared, behind a mutex, and its arrays are not changed once recorded.
Signed-off-by: Jono Prest <jjprest@gmail.com>
67eb3bc to
94bd206
Compare
Stacked on #9192.
When a module first uses a dependency,
Envbuilds that dependency's components and copies every value of its interface with the module path substitution. Dependents read only a few of them: on a 552 module React app about 5% of those values are ever read.For the components of a
.cmisignature, values are now table cells that make the copy on first read. This uses the same approach as #9192 to keep output identical:.cmi,.cmj, JS and.cmt, stays the same.bscand the first use of an interface in a build are unchanged.opentables take the cells too: an open keeps a function giving each component's binding, andEnv.copy_typesoverrides go in a small table checked first.The gain is real but modest, and this adds a fair amount of code to
env.ml(about 300 lines). Paired benchmark, 20 interleaved clean builds per project, against #9192, user CPU with bootstrap 95% CI (for the full version, deferring types and labels too; this values only version measured the same head to head, with about 30% less code):Wall time at default domains is within noise on two of the three projects. Allocation drops about 2% on the React app. So this is a few percent of CPU, and only in the long running rewatch process. Happy to drop it if that isn't worth the extra machinery in
env.ml.Testing:
ounit_deferred_components_tests.ml: eager vs deferred components of every runtime interface compared as marshalled results, unread values still reserving their ids, the fallback for a wrong count, a copy that raises,Env.copy_typesthrough an open, and whole compiler requests (outputs,.cmtand error messages with functors, aliases, include,module type of, recursive modules, shadowing, first class modules) eager vs deferred, also on 4 domains at once..cmi,.cmj,.ast,.cmtand.cmtiare byte identical to master across three production codebases and their dependencies, at 1 and the default number of domains.make testandmake test-rewatchpass.