Runtime memory snapshots (-d / --dump) |
Counts for objects, shapes/properties, atoms, strings, arrays/elements, functions/bytecode and backing stores; owned bytes and buffer capacity where measurable; runtime allocator live allocation count/bytes where supported. |
Record the snapshot phase, runtime identity, resource coverage and accounting basis. Deduplicate shared storage. Keep logical counts, requested bytes, capacity and usable bytes separate. |
Allocation events (-T / --trace) |
Allocation / reallocation / free events, event sequence, allocation identity, requested size, result and failures where observable; previous/new identity and size for reallocations where available. |
Trace from runtime creation through teardown. State exactly which allocation paths are covered. Mark partial coverage and dropped events/output failures; object creation counts are not allocator events. |
Runtime / Context lifecycle timing (-q -d) |
Separate durations for Runtime creation, Context creation, Context destruction and Runtime destruction, with iteration count and raw repeated samples. |
Identify timer and units explicitly (CPU time vs monotonic wall time). Report summaries with their aggregation rule; keep process startup separate from API lifecycle cost. |
| Operation benchmarks |
Per-case elapsed time, iteration/operation count, ns/op, repeated independent run results, minimum and median with variation, and per-case ratios against a recorded baseline. Start with loop, property access, array, call and numeric workloads from the pinned tests/microbench.js. |
Preserve benchmark bodies; adapt only host facilities as needed. Measure cold start, parse/compile and steady-state execution separately where the harness supports that separation. Record successful execution/result checks, failures and unsupported cases. |
| Reproduction metadata |
Report schema version, engine version/commit, reference release, workload/harness hashes, CPU/architecture, OS, pointer width, Rust/C compiler versions, build profile/optimization flags, enabled features, profiler mode, timer, warm-up and repetition policy. |
Save alongside every result so comparisons use matching workloads, environments and measurement definitions. |
Goal
Establish an opt-in profiler and reproducible benchmark baseline before optimizing quickjs-oxide. The collected data should tell us where memory is retained, where allocations occur, how much initialization costs, and which operations are slow relative to the pinned QuickJS 2026-06-04 reference and previous Oxide revisions.
This issue tracks the observability foundation and its data contract. The interfaces below are proposed, not implemented functionality.
Data we will collect
-d / --dump)-T / --trace)-q -d)ns/op, repeated independent run results, minimum and median with variation, and per-case ratios against a recorded baseline. Start with loop, property access, array, call and numeric workloads from the pinnedtests/microbench.js.Accounting rules
HeapCountsandGcStatscapabilities. GC node statistics describe a collection; they do not establish complete byte accounting.null/unavailable, with a reason. Never substitute zero or presentnode_count * size_ofas total memory usage.unsafe_code = "forbid"policy. Assess safe allocation instrumentation coverage before committing to full allocator interception; usecoverage=partialwhen appropriate.Collection and benchmark workflow
std/oscompatibility.Deliverables / acceptance