Skip to content

fix(bench): render contacts in contact-book benchmark - #468

Merged
Mohamed Mansour (mohamedmansour) merged 1 commit into
mainfrom
mohamedmansour-fix-contact-book-bench-route-e68
Aug 24, 2026
Merged

fix(bench): render contacts in contact-book benchmark#468
Mohamed Mansour (mohamedmansour) merged 1 commit into
mainfrom
mohamedmansour-fix-contact-book-bench-route-e68

Conversation

@mohamedmansour

Copy link
Copy Markdown
Contributor

Problem

crates/webui/benches/contact_book_bench.rs scales contacts / filteredContacts to 10 / 100 / 1,000 entries, but every render call used RenderOptions::new("index.html", "/").

Route selection is request-path driven — the state page field only controls sidebar highlighting. / resolves to cb-page-dashboard, which renders recentContacts capped at MAX_RECENT_CONTACTS (5). The scaled arrays were never traversed, so output stayed flat at ~24 KB at every scale and the reported throughput measured nothing about list rendering.

Measured on main (no plugin):

Contacts / output bytes
10 24,237
100 24,210
1,000 24,253

The Node addon benchmark already uses requestPath: "/contacts"; the Rust benchmark had drifted.

Fix

Render /contacts, which resolves to cb-page-contacts and loops the full contact list, emitting one cb-contact-card per contact with 12 dynamic attributes each.

Contacts /contacts output bytes with FAST plugin
10 34,007 57,874
100 251,727 385,566
1,000 2,431,665 3,671,155

Changes, all in the one benchmark file:

  • REQUEST_PATH constant (/contacts) threaded through all six RenderOptions sites — three benchmark groups plus the summary pass.
  • Fixture page"contacts" so sidebar state matches the rendered route.
  • Criterion groups renamed contact_book_render*contact_book_contacts_render*, so stale dashboard baselines cannot be compared against the new workload.
  • Startup guard validate_output_scales_with_contacts renders CONTACT_COUNTS in ascending order and fails unless output strictly increases. It fails on the old route with an actionable message, so this regression cannot silently return.
  • Recalibrated buffer constants against the measured /contacts workload (see below).

Guard proof

Temporarily pointing REQUEST_PATH at / — the pre-fix behavior — fails immediately:

thread 'main' panicked at crates\webui\benches\contact_book_bench.rs:671:9:
benchmark route / does not scale with the contact count: 100 contacts produced
24209 bytes, which is not more than the 24236 bytes produced by the previous,
smaller scale
error: bench failed

With /contacts restored, cargo bench -p microsoft-webui --bench contact_book_bench -- --test passes.

Buffer sizing

The old constants were calibrated for the dashboard route and under-allocated the real workload by 4–5×, forcing repeated reallocation inside the warmup render.

Constant Before Measured After Rationale
BYTES_PER_CONTACT 512 ~2,422 B 2,432 Marginal cost per contact: (2,431,665 − 251,727) / 900
BYTES_PER_CONTACT_WITH_PLUGIN 768 ~3,651 B 3,712 (3,671,155 − 385,566) / 900
BASE_HTML_BYTES 8,192 ~9,787 B 12,288 34,007 − 10 × 2,422
BASE_HTML_BYTES_WITH_PLUGIN 16,384 ~21,314 B 24,576 57,874 − 10 × 3,651

Resulting slack is 0.5–7.6% — enough that no scale reallocates, without retaining excessive memory.

  • WRITER_HEADROOM (1,024) is unchanged. Rendering is deterministic, so the timed output matches the warmup byte-for-byte; the headroom only absorbs incidental drift and 1 KiB is adequate.
  • SUMMARY_WRITER_CAPACITY was 64 KiB with a stale comment claiming a ~443 KiB peak. The real peak is ~3.5 MiB. It is now derived from MAX_CONTACT_COUNT × BYTES_PER_CONTACT_WITH_PLUGIN + BASE_HTML_BYTES_WITH_PLUGIN (a const block, no recursion), so it stays in sync if CONTACT_COUNTS changes.

Validation

cargo bench -p microsoft-webui --bench contact_book_bench -- --test          # passes
cargo bench -p microsoft-webui --bench contact_book_bench -- contact_book_contacts_render --quick
cargo xtask check

New group IDs, now scaling as expected:

contact_book_contacts_render/contacts/10                time: 54.234 µs
contact_book_contacts_render/contacts/100               time: 466.73 µs
contact_book_contacts_render/contacts/1000              time: 4.9881 ms
contact_book_contacts_render_fast_plugin/contacts/10    time: 86.826 µs
contact_book_contacts_render_fast_plugin/contacts/100   time: 570.53 µs
contact_book_contacts_render_fast_plugin/contacts/1000  time: 6.8939 ms

cargo xtask check: license-headers, fmt, clippy, deny, test, build, build (wasm), build (examples), and bench (validate) all pass. The docs phase fails locally with PROJ-C013: Adapter module graph is incomplete or inconsistent; this reproduces identically on pristine main with this change stashed, so it is a pre-existing local baseline failure and is not addressed here.

Scope

Benchmark correctness only — one file, no lockfile drift, no product code. This makes no performance claim about the framework; it repairs the workload that later benchmarking work depends on.

The contact-book benchmark scaled `contacts`/`filteredContacts` to
10/100/1,000 entries but rendered `RenderOptions::new("index.html", "/")`.
Route selection is request-path driven, so `/` resolved to
`cb-page-dashboard`, which only emits `recentContacts` capped at five. The
scaled arrays were never traversed and output stayed flat at ~24 KB across
all three scales, making the reported throughput meaningless.

Render `/contacts` instead, which resolves to `cb-page-contacts` and loops
the full contact list. Output now scales 34 KB / 252 KB / 2.43 MB.

- Route every render and summary sample through a `REQUEST_PATH` constant.
- Set the fixture `page` field to `contacts` so sidebar state matches the
  rendered route.
- Rename the render groups to `contact_book_contacts_render*` so stale
  dashboard baselines cannot be compared against the new workload.
- Add a startup guard that renders `CONTACT_COUNTS` in ascending order and
  fails unless output strictly increases, so a route regression cannot
  silently return.
- Recalibrate the writer pre-allocation constants against the measured
  `/contacts` output, and derive the summary writer capacity from the
  largest benchmarked scale.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@mohamedmansour
Mohamed Mansour (mohamedmansour) merged commit f9409f7 into main Aug 24, 2026
36 checks passed
@mohamedmansour
Mohamed Mansour (mohamedmansour) deleted the mohamedmansour-fix-contact-book-bench-route-e68 branch August 24, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes the Rust contact_book_bench workload so it actually benchmarks contact list rendering by rendering the /contacts route (which traverses the full filteredContacts list) instead of / (dashboard, capped at 5 recent contacts). This makes output size and throughput scale with contact count, aligning the benchmark’s intent with the rendered route behavior.

Changes:

  • Introduces a single REQUEST_PATH (/contacts) and threads it through all render sites (bench groups + summary pass).
  • Updates benchmark fixture state (page: "contacts") and renames Criterion group IDs to reflect the new workload.
  • Adds a startup validation guard (validate_output_scales_with_contacts) plus recalibrates writer capacity constants for the /contacts output sizes.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants