Skip to content

perf(buffer): 79.7M is_registered_buffer probes for 9 buffers (90 true positives) — 2.8% of native tsc; the diag itself sizes a 1024-bit Bloom at 0% FP #10694

Description

@proggeramlug

Summary

Compiling a two-line file with a natively compiled tsc issues 79,691,777 is_registered_buffer probes in a 7.8 s run — roughly 10 million per second — to answer a question about a set that never holds more than 9 buffers. 90 of those probes are true positives.

is_registered_buffer_slow is 2.8% of leaf samples in that run.

Measured

Perry 0.5.1596 (fix/10656-codepointat-linear, i.e. with #10656/#10685 applied), macOS arm64, using the runtime's own PERRY_BUFFER_DIAG instrument:

[buffer-diag] probes=79691777 admits=26198956 (32.88 %) rejected=53492821 (67.12 %)
              true_positives=90 (0.000344 % of admits)
  window   [0x5abfc600008, 0x5ac0204f938] span  90.3 MB
  probed   [0x5abf7a30030, 0x5ac216c9f48] span 668.6 MB -- window covers 13.5 % of the probed range
  registrations=9 unregistrations=9 live_max=9
  => a 1024-bit/3-hash Bloom holding all admissions would be 0.0 % false-positive

Workload: ./tsc --noEmit demo.ts where demo.ts is two lines. Input file:

type Config = { port: number };
const cfg: Config = { port: "8080" };

Two distinct problems

1. The gate lets 26.2 M probes through to a 9-element hash set. BUFFER_LIKE_ADDR_WINDOW is doing real work — it rejects 67.12% inline, exactly as designed — but the surviving 32.88% each pay a function call, a thread-local resolution, a RefCell borrow and a hash lookup to discover, 99.999656% of the time, that the answer is no. The window spans 90.3 MB inside a 668.6 MB probed range, so a min/max bounding box simply cannot separate 9 addresses from the heap around them.

The instrument already names the fix and sizes it: a 1024-bit, 3-hash Bloom filter over registered addresses would be 0.0% false-positive on this workload — 128 bytes of state replacing 26.2 M hash probes. It fits the same soundness contract as the window (every writer arms it before publishing; a negative is authoritative, a positive falls through to the existing set).

2. The deeper question: why 79.7 M probes for 9 buffers? Nothing in this workload is buffer-shaped — it is a type-check of two lines of TypeScript. At ~10 M probes/second something on a very hot path is asking "is this a registered buffer?" about values that are overwhelmingly not buffers and never could be. is_registered_buffer has ~200 call sites per its own comment; the probe volume suggests one of them sits in a generic value/type ladder that runs per property access or per value touched.

Fixing (1) makes each probe ~free. Fixing (2) removes them. (2) is the larger win and is likely a small change once the caller is identified — a PERRY_BUFFER_DIAG variant that samples call-site backtraces would find it immediately.

Why this is worth doing

is_registered_buffer_slow is 2.8% of the run on its own, but it is one member of a family: predicates answering "what kind of pointer is this?" are 18.5% of the post-fix profile —

symbol share
is_registered_box_ptr 5.2%
is_registered_buffer_slow 2.8%
classify_heap_generation_uncached 1.3%
resolve_strategy_slow 1.2%
get_parent_class_id 1.2%
is_class_object_ptr 1.1%
keys_find_slot_by_bytes 1.0%
is_registered_map, classify_arena, … rest

This one is the most clear-cut instance because the ratio is so extreme (90 hits in 79.7 M probes) and the runtime already ships the instrument that proves it.

Reproduction

PERRY_BUFFER_DIAG=/tmp/bufdiag.log ./tsc --noEmit demo.ts
tail -6 /tmp/bufdiag.log

Related: the same probe family is discussed in #10688's context; GC census recorded 147 MB of side tables against a 23 MB live heap, which is the memory face of this design.

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

    performanceRuntime, compile-time, build-size, or memory performance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions