exp 135: writer-isolate dispatch wall vs SQLite step wall audit#110
Open
danReynolds wants to merge 2 commits into
Open
exp 135: writer-isolate dispatch wall vs SQLite step wall audit#110danReynolds wants to merge 2 commits into
danReynolds wants to merge 2 commits into
Conversation
Closes the writer-isolate wall vs SQLite wall split candidate in signals.json#stream-rerun-dispatch.blockedOnMeasurement. Adds three profile-mode counters in the writer isolate (writerHandlerUs, writerSqliteUs, writerHandlerCount), exposes them cross-isolate via Database.snapshotWriterProfileCounters() backed by a new snapshot/reset RPC pair on the writer protocol, and ships a focused audit harness that reports the breakdown on the existing A11c and keyed-PK scenarios. Headline reading: on A11c overlap the writer-isolate handler is only ~22-25% of writer-side burst wall (rest is main-isolate microtask scheduling); within the writer, SQLite step is ~55-58% and Dart dispatch is ~42-45% of writer handler. Structural ceiling for removing all writer-side Dart dispatch on overlap is ~9-11% of total wall — same per-benchmark decision threshold edge as exp 121's invalidation traversal ceiling. Future stream-rerun-dispatch work needs the remaining completion-side scheduling counter before another implementation pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds EXP-135 measurement infrastructure to split writer-isolate “handler wall” into (a) time spent inside SQLite-driving FFI calls and (b) remaining Dart-side dispatch time, and wires this into the existing audit workload suite to quantify optimization headroom.
Changes:
- Extend
ProfileCounterswith writer-isolate counters (writer_handler_us,writer_sqlite_us,writer_handler_count) and update snapshot/reset + tests. - Add writer-protocol snapshot/reset RPCs and
DatabaseAPIs to retrieve/reset writer-isolate counters cross-isolate. - Add a new profile harness (
writer_step_wall_audit.dart) + generated aggregate markdown, and update experiment docs/signals/history to record EXP-135.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/profile_counters_test.dart | Updates expectations for new writer_* keys and adds a basic round-trip test for snapshot/reset. |
| lib/src/writer/writer.dart | Adds Writer helper methods to snapshot/reset writer-isolate counters via writer protocol. |
| lib/src/writer/write_worker.dart | Implements new writer request/response types and instruments handler/SQLite wall counters in the writer isolate. |
| lib/src/profile_counters.dart | Adds writer-side counter fields and includes them in snapshot/reset plumbing. |
| lib/src/database.dart | Exposes new public Database APIs to snapshot/reset writer-isolate counters. |
| benchmark/profile/audit_workloads.dart | Resets writer counters before workloads and merges writer snapshots into the main counter map. |
| benchmark/profile/writer_step_wall_audit.dart | New audit harness to format writer handler vs SQLite vs dispatch breakdown. |
| benchmark/profile/results/exp-135-writer-step-wall-aggregate.md | Checked-in aggregate output from the new audit harness. |
| experiments/135-writer-step-wall-audit.md | New experiment writeup documenting hypothesis, approach, and results. |
| experiments/signals.json | Records EXP-135 outcomes and updates measurement gates for dispatch-related work. |
| experiments/README.md | Adds EXP-135 to the experiment index. |
| experiments/JOURNAL.md | Adds a note about cross-isolate counter export pattern via snapshot RPC. |
| docs/experiments/history.json | Regenerates experiment history to include EXP-135. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- ProfileCounters writerHandlerUs doc references the actual public accessor (Database.snapshotWriterProfileCounters → Writer.snapshotWriterCounters); the original prose pointed at a name that doesn't exist on Writer. - Database.snapshotWriterProfileCounters / resetWriterProfileCounters now run under the writer mutex (writer.locked) so they serialize with execute() / transaction() the same way other public Database write methods do. Without it a snapshot could land between the BEGIN and COMMIT messages of an in-flight transaction and sample partial state. - writer_step_wall_audit.dart clamps dispatch_us at zero. handler_us and sqlite_us come from independent stopwatches, so a marginal handler could in theory round to sqlite_us > handler_us and produce a negative fraction in the rendered markdown. Clamping makes the report robust against that measurement artifact. - test/database_test.dart guards the new writer-counter API surface: one test asserts the snapshot returns the EXP-135 keys, another that reset+snapshot round-trips without throwing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hypothesis
After exp 120 / exp 121, the writer-isolate handler wall on stream
workloads is mostly SQLite step time, with Dart-side dispatch (param
allocation, dirty-table marshalling, message build/send) at a small,
optimization-sensitive but per-benchmark-sub-threshold share. If
true, writer-side dispatch should not be the next implementation
target on currently-measured workloads, and the structural ceiling
for remove all writer-side Dart dispatch should be close to exp
121's invalidation-traversal ceiling (10–15% of A11c overlap wall).
This experiment ships the writer dispatch wall counter listed in
signals.json#stream-rerun-dispatch.blockedOnMeasurement(one oftwo named gates blocking the next dispatch-area implementation
experiment).
Approach
Three small additions, all gated behind
kProfileMode:writerHandlerUs,writerSqliteUs,writerHandlerCountfields onProfileCounters. The existingsnapshot/diff/reset plumbing carries the new keys.
WriterCountersSnapshotRequest/WriterCountersResetRequestrequest types on the writer protocol;Database.snapshotWriterProfileCounters()exposes the round-tripto audit harnesses. Snapshot/reset bookkeeping is excluded from
the per-handler stopwatch so it does not contaminate the measured
wall.
a per-handler stopwatch (handler_us); FFI calls that drive SQLite
(
resqliteExecute,resqliteRunBatch,resqliteRunBatchNested,the cached transaction-control stmts,
resqliteExecfor SAVEPOINT/ RELEASE / ROLLBACK TO, prepare+step inside
_handleTxQuery) gothrough a
_measureSqlitehelper that accumulatessqlite_us.dispatch_us = handler_us − sqlite_us.A new harness
benchmark/profile/writer_step_wall_audit.dartformats the breakdown on the existing A11c (baseline / disjoint /
overlap) and keyed-PK scenarios from
audit_workloads.dartso thefractions align structurally with exp 119 / exp 121.
Full implementation detail in
experiments/135-writer-step-wall-audit.md.Results
Three repeated passes (a/b/c) of the A11c scenarios:
Sanity:
dispatcher_parked_total = 0,dispatcher_wake_retry_total = 0,and
dispatcher_max_parked_concurrent = 0on every workload —exp 120 / exp 122 still hold post-instrumentation.
Headline reading: on A11c overlap the writer-isolate handler is only
~22-25% of writer-side burst wall (rest is main-isolate microtask
scheduling); within the writer, SQLite step is ~55-58% and Dart
dispatch is ~42-45%. Structural ceiling for removing all
writer-side Dart dispatch on overlap is ~9-11% of total wall —
same per-benchmark decision threshold edge as exp 121's invalidation
traversal ceiling (10-15%). Combined, even fully eliminating both
saves ~20-25% of overlap wall, with the remaining ~75% sitting on
the main isolate.
Aggregate file:
benchmark/profile/results/exp-135-writer-step-wall-aggregate.md.Outcome
In Review — measurement.
Closes the
writer-isolate wall vs SQLite wall splitcandidate insignals.json#stream-rerun-dispatch.blockedOnMeasurement. Only thecompletion-side microtask scheduling cost counterremains. Futurewriter-side dispatch experiments need to clear the ~9-11% overlap
wall ceiling reproducibly on a 5-run release suite.
Reopen the writer-side dispatch direction if a new workload pushes
the per-handler dispatch share above ~50% of writer handler, or if a
specific bounded change targets the overlap-only
getDirtyTableDependenciesdelta (~17 µs/handler vs ~10 µs on disjoint).
Test plan
dart analyzecleandart testsuite passes (232 tests)dart run benchmark/run_profile.dartreportsunchanged dispatch floors (~5 µs reader, ~9 µs writer)
benchmark/profile/writer_step_wall_audit.dartran 3× under-DRESQLITE_PROFILE=truewith stable per-handler dispatch numbersbenchmark/profile/dispatch_pressure_audit.dart(exp 119) andbenchmark/profile/invalidation_traversal_audit.dart(exp 121)still produce consistent reports against the modified
audit_workloads.dartdart run benchmark/check_experiment_signals.dartpassesdart run benchmark/check_generated_data.dartpasses afterregenerating
docs/experiments/history.json🤖 Generated with Claude Code