ReviewOS

home-lang/home

TypeScript frontend: recover current-source benchmark regressions

#837
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Context

Discovered while making the published benchmark claims traceable under #836.

A fresh full admitted run at source commit 6c2abccbf used the pushed median-reporting harness, a stripped ReleaseFast home-tsc, TypeScript 6.0.3, and native TypeScript 7.0.2. It retained 30 fresh processes per compiler per workload after three warmups in rotating order: 20 workloads, 600 round files, 1,800 successful samples. Executable provenance was unchanged before admission and after measurement.

Host: Apple M2 Pro / Mac14,9, 10 logical cores, Darwin 25.3.0 arm64. Result ID: 20261007T141452Z.

Current result

Home has the lowest median on only 8/20 workloads. The largest regressions versus the faster pinned TypeScript competitor are:

Workloadtsgo medianHome medianResult
type_predicates_large442.8 ms44,012.1 msHome 99.40× slower
type_predicates78.8 ms694.4 msHome 8.81× slower
null_safe_access69.1 ms328.4 msHome 4.75× slower
control_flow64.3 ms216.8 msHome 3.37× slower
class_hierarchy59.4 ms198.7 msHome 3.34× slower
interface_composition72.2 ms204.2 msHome 2.83× slower

The old site claim that Home led 20/20 is therefore not current-source evidence and is being removed under #836 rather than preserved.

Requirements

  • Profile the current type_predicates_large workload without changing its generated project or admission controls.
  • Identify the source-level regression(s), with a fixed baseline and candidate binary from the same toolchain.
  • Optimize the general compiler path; no benchmark-name checks, corpus weakening, skipped diagnostics, or reduced semantic work.
  • Keep all positive and negative admissions byte-equivalent to the pinned compilers.
  • Run focused reversed-order A/B measurements before and after each accepted change; retain every sample.
  • Re-run the full 20-workload same-machine suite before updating public claims.

Acceptance

The full admitted suite is rerun with the same pinned competitors and methodology, raw evidence is retained, and any public performance claim matches that new run. Improvements must not regress TypeScript conformance, diagnostic admission, or another benchmark family.

9 days ago

The regression baseline is now pushed and permanently traceable.

Current-source full-suite result: 20261007T141452Z, source 6c2abccbf, stripped ReleaseFast home-tsc, 30 interleaved rounds after three warmups, all 1,800 samples retained, provenance unchanged before admission and after measurement. Home's executable SHA-256 is bbb407f640151df4d15f856d3a78d1e3f42693c3543f5328d985c8975df5564f.

Raw evidence and checksums: https://github.com/home-lang/home/raw/main/bench/vs_tsgo/evidence/20261007T141452Z.tar.gz Archive SHA-256: 7ff6a7a0a7d9ee3cb19269274abe70a79566e5a32c45c0c0ed981488257f4a15

The public README and docs now report the 8/20 current result instead of the historical 20/20 claim (870b4e802), and CI retains future raw + packaged evidence for 90 days (c9eea785b). The next step is profile-backed diagnosis of type_predicates_large; no benchmark/corpus/admission change will be used as a performance fix.

9 days ago

Post-fix root cause and full-suite evidence are now on main.

Root cause and fix

A direct-checkout bisect under the 3,840 MB guard identified e2b727c9cfbc2f4fe4803a43c31dc6a6cd573411 (feat(ts): trace implicit this recoveries (#783)) as the first bad commit; parent 2e15da27c completed the unchanged 2,048-family project in 0.24 s CPU, while the first bad revision took about 47 s.

The regression was a general source-size bug, not a benchmark-specific path: explicitNoImplicitThisIsDisabled() rescanned the complete source for every identifier/this expression. On the 3 MB project this made checking effectively quadratic. Instrumentation separately ruled out the suspected diagnostic-list scan: it observed 98,304 calls with zero candidates and a final diagnostic length of zero.

ebffe93d0fff8d8b1da1af5145ea0a2a85c380e0 fixes this by adding @noImplicitThis to the existing one-pass source-marker index and caching the exact directive result in SourceFacts. The cache resets when the source changes; directive parsing and recovery semantics are unchanged. The unchanged scale project fell from 45.20 s to 0.59 s CPU (about 77× faster).

Complete admitted rerun

Result 20261007T161511Z measures source ebffe93d0 with 20 admitted workloads, 30 rotating-order rounds after three warmups, and all 1,800 successful samples retained. Compiler/tool provenance was verified unchanged before admission and after measurement.

Home now has the lowest median on 19/20 workloads. The sole remaining loss is:

Workloadtsc 6.0.3native TS 7.0.2Home 0.1.0Result
type_predicates_large1,202.1 ms412.8 ms593.0 msHome 1.44× slower

The public table and evidence were pushed in ff15995f00220d13ceb065a6b781d79b53b75f6a.

Evidence: https://github.com/home-lang/home/raw/main/bench/vs_tsgo/evidence/20261007T161511Z.tar.gz Archive SHA-256: 3ce9703591f967f081aa35bf1e704b88f83dae412e7ad51699a8bd99e3e79c8e Measured Home executable SHA-256: 8e13b2e0f2e41e8e3fe1e5d01e1f090a85b85f6ac582555599fd4409e7128e63

Verification: 104/104 benchmark-harness tests; all 602 archive checksums; deterministic byte-identical archive regeneration; zero contributor paths in published metadata; all 50 displayed table rows machine-checked against retained medians/ratios; Pickier clean; 96-page production docs build; docs path and metadata gates clean.

Next benchmark matrix

This issue remains open for the last 1.44× loss and for a fair matrix expansion. Once exact upstream repositories/CLIs are verified and buildable, the same-run matrix should add Theo's Rust tsc-rs/ts-rust, the C++ TypeScript port, and Bun's bun check. They must use the identical admitted corpus, semantics, warmups, repeat count, machine, rotating schedule, provenance checks, and retained raw artifacts; numbers from screenshots or unrelated runs will not be reused.

9 days ago

Acceptance is complete on main.

Final root cause and fix

History bisection isolated 6a947ead53c0b14eb8b563a082b3d4c0a9e949ff as the first remaining regression after the earlier @noImplicitThis fix. ensureForwardOverloadSet scanned every statement in the source root at every ordinary identifier call merely to prove that a unique name was not an overload. The 2,048-family project has 8,192 uniquely named functions and corresponding calls, turning negative lookup into quadratic work.

5f90572c77c2c8a21d8ef31337eaf17f2fc4664e replaces those repeated scans with one lazy source-root index containing only duplicate function names with at least one bodyless overload signature. Signature checking remains lazy at the original call site, preserving contextual typing and diagnostic order. An eager precheck design was rejected: it slowed the official workload to 922.8 ms and failed two contextual-overload tests.

Verification:

  • complete checker suite: 4,472/4,472;
  • benchmark harness: 104/104;
  • unchanged large-corpus diagnostics: exact empty-output match before and after;
  • focused admitted result 20261007T183136Z: Home 305.6 ms, native TS 420.3 ms, tsc 1,192.4 ms;
  • full admitted result 20261007T183321Z: 20/20 Home wins across 1,800 retained samples;
  • repaired full-suite row: Home 308.3 ms vs native TS 419.7 ms vs tsc 1,229.8 ms.

68ab901de16a783739782723f261806143f35571 publishes the updated README/docs and durable evidence archive.

Evidence: https://github.com/home-lang/home/raw/main/bench/vs_tsgo/evidence/20261007T183321Z.tar.gz Archive SHA-256: de0068831ee0d037b9c103232d7b3eeb51e140c984f8d6be54b866dd355e1cfe Measured Home executable SHA-256: 2423c443af320c1334a0ad19264ef7d6a9ad7d0a323846baedaf3bb6dc4ae77c

All 602 published checksums verify; deterministic regeneration is byte-identical; Pickier passes; the 96-page production docs build passes. The requested Rust/C++/Bun-check expansion is now separated into #838 so this regression issue can close without conflating a new benchmark scope.

9 days ago

Verified the current winning archive 20261007T183321Z directly before updating the benchmark directory README under #837 / #836.

  • All 602 entries in its SHA256SUMS match the stored payload bytes.
  • The archive contains 600 raw round files and 1,800 successful samples: 30 samples for each of the three compilers on every one of the 20 workloads.
  • Recomputing medians from all samples confirms Home's lowest median on 20/20 workloads. The narrowest ratio is 1.36× on type_predicates_large; the widest is 12.62× on startup.
  • This is the existing same-run Apple M2 Pro / macOS ARM64 measurement at 5f90572c7, with TypeScript 6.0.3 and native TypeScript 7.0.2. No new timing run or unmeasured-platform claim is implied.

The root README and performance document already show this result, but bench/vs_tsgo/README.md still listed the earlier 20261007T141452Z 8/20 snapshot as current. The documentation commit replaces that stale row with the verified current result and links its evidence archive and detailed report.

9 days ago

Pushed f0e998512 directly to origin/main as Chris Breuer, with a conventional issue-linked commit and no coauthors.

The benchmark directory README now links the verified 20261007T183321Z 20/20 result, its raw archive, machine, source revision, sample counts, and narrowest/widest median leads. The root README table and detailed performance document already agree with it. Archive verification passed all 602 payload checksums and recomputed all 20 median winners from every retained sample.

git diff --check passed. The required repository-wide Pickier run reports 20,516 findings (10,181 errors and 10,335 warnings) across the existing source corpus; none are in the edited Markdown file. This documentation-only commit does not change compiler behavior or benchmark inputs.

Sign in to comment on this issue.