Skip to content

perf(handler): centralize HTML attribute writing in ResponseWriter - #467

Merged
Mohamed Mansour (mohamedmansour) merged 2 commits into
microsoft:mainfrom
mohamedmansour:mohamedmansour-split-performance-prs
Aug 24, 2026
Merged

perf(handler): centralize HTML attribute writing in ResponseWriter#467
Mohamed Mansour (mohamedmansour) merged 2 commits into
microsoft:mainfrom
mohamedmansour:mohamedmansour-split-performance-prs

Conversation

@mohamedmansour

Copy link
Copy Markdown
Contributor

What

Adds hidden write_attribute / write_boolean_attribute methods to the ResponseWriter trait, backed by centralized append helpers and four macro_rules! generators in a new crates/webui-handler/src/response_writer.rs.

Buffered hosts adopt the macros and drop their hand-written writer implementations. Six duplicated ResponseWriter impls are removed (webui-ffi, webui-python, webui-press, webui-cli, webui-wasm, webui, plus webui-node's BufferedWriter and the demo server's shell writer).

Writers with distinct semantics — StreamingSink, BufferSink, StreamingWriter, and the Node CallbackWriter — implement the methods directly so threshold flushing and stream forwarding are preserved.

Why

Emitting one HTML attribute previously cost five write() calls through a dyn ResponseWriter vtable (" ", name, "=\"", value, "\""). For a buffered host, all five collapse into a direct push_str on the backing String/Vec<u8>.

This is the structural prerequisite for the later handler render-pipeline layers, which are attribute-bound.

Evidence

Correctness — byte-identical output (deterministic)

A temporary harness rendered a mixed protocol (component attrs, attribute templates, boolean attrs, nested for loop with a per-item attribute) at 10 / 100 / 2,000 items, on the merge base and on this branch, using a generic writer that implements only write():

items revision write() calls bytes FNV-1a
10 origin/main 112 433 489c33c436b03492
10 this branch 112 433 489c33c436b03492
100 origin/main 922 3043 e48fab1207c9a292
100 this branch 922 3043 e48fab1207c9a292
2000 origin/main 18022 63943 ec91d5c009de1b8a
2000 this branch 18022 63943 ec91d5c009de1b8a

Identical hash, byte count, and call count — the write()-based defaults are behaviorally indistinguishable from the previous inline code, so external ResponseWriter implementors are unaffected.

Dispatch reduction — the actual change (deterministic)

Same render, generic writer vs. a macro-generated writer, output asserted equal:

items generic write() calls macro write() calls eliminated reduction
10 112 52 60 −53.6%
100 922 412 510 −55.3%
2000 18022 8012 10010 −55.5%

Exactly 5 virtual dispatches removed per attribute (2,002 attributes × 5 = 10,010 at the 2,000-item scale).

Wall-clock — no claim made

Commands:

cargo bench -p microsoft-webui-handler --bench handler_bench
cargo bench -p microsoft-webui        --bench contact_book_bench

Ran 3 interleaved base/branch cycles with prebuilt binaries at high priority (24-core dev machine, ~22% background load). The measurements are not usable: run-to-run spread across identical repeated runs of the same binary reached 31%, exceeding every observed between-variant delta (max 13%). contact_book_protocol_parse — pure protobuf decode, untouched by this PR — "regressed" 43% on one pass, confirming the noise floor.

No performance improvement is claimed from timing data. The deterministic dispatch counts above are the evidence for this PR. Wall-clock benchmarking should be repeated on a quiet machine in the layer where it is load-bearing.

Allocation behavior is unchanged: no new allocations are introduced on any path, and the macro writers append into the caller's existing buffer.

Tests

  • New generated_string_writer_methods_preserve_exact_attribute_output asserts exact output (" data-id=\"42\" disabled") through the macro path.
  • cargo test -p microsoft-webui-handler — 428 + 29 passing.
  • cargo xtask check: license-headers, fmt, clippy, proto, deny, test, build, build (wasm), build (examples), bench (validate) all pass.
  • The docs step fails with PROJ-C013: Adapter module graph is incomplete or inconsistent from the esbuild projection adapter. This reproduces identically on a pristine origin/main checkout and is unrelated to this PR, which changes no JavaScript.

Notes

  • ResponseWriter gains only #[doc(hidden)] methods with defaults — no breaking change for external implementors.
  • DESIGN.md documents the macro contract and when a host should implement the methods directly.
  • No dependency, Cargo.lock, or pnpm-lock.yaml changes.

Add hidden `write_attribute`/`write_boolean_attribute` methods to
`ResponseWriter` with `write()`-based defaults, plus centralized
append helpers and macros that let buffered hosts emit attributes with a
direct buffer append instead of five virtual dispatches.

Adopt the macros across every buffered host writer, removing six
duplicated `ResponseWriter` implementations in webui-ffi, webui-python,
webui-press, webui-cli, webui-wasm, webui, webui-node, and the demo
server. Streaming and callback writers override the methods directly so
their flush and forwarding semantics are preserved.

Output is byte-identical: the default trait methods emit the same
sequence as before, and the macro-generated methods write the same bytes
without routing through `write()`.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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

This PR centralizes HTML attribute emission in webui-handler by adding hidden ResponseWriter methods for quoted and boolean attributes, plus shared append helpers and macro generators to let buffered hosts inline optimized attribute writing and reduce virtual dispatch overhead in the render pipeline.

Changes:

  • Added ResponseWriter::write_attribute / write_boolean_attribute (hidden, defaulted) and switched handler attribute emission to call the new method.
  • Introduced centralized attribute append helpers + macro_rules! generators, and migrated multiple buffered host writers to macro-generated implementations.
  • Updated streaming/callback writers (streaming, WASM, Node) to implement the hidden attribute methods directly to preserve flushing/forwarding semantics; added/updated benches and tests and updated DESIGN.md.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
examples/demo/server/src/shell.rs Replaces a local ResponseWriter impl with a macro-defined string writer.
DESIGN.md Documents the new attribute-writing contract and when to override hidden methods.
crates/webui/src/streaming.rs Implements optimized attribute methods for StreamingWriter while preserving flush behavior.
crates/webui/src/server.rs Replaces an internal MemWriter with a macro-defined string writer.
crates/webui/benches/contact_book_bench.rs Fixes bench command docs and adds macro-generated attribute methods to bench writer.
crates/webui-wasm/src/handler.rs Uses macro-defined string writer and adds optimized attribute methods to CallbackWriter.
crates/webui-python/src/lib.rs Replaces bytes writer impl with macro-defined bytes writer and updates construction callsite.
crates/webui-press/src/build.rs Replaces local string writer impl with a macro-defined string writer.
crates/webui-node/src/lib.rs Replaces buffered writer impl with macro-defined writer and adds optimized attribute methods to callback writer.
crates/webui-handler/src/streaming/owned.rs Adds optimized attribute methods to BufferSink.
crates/webui-handler/src/streaming/mod.rs Adds optimized attribute methods to StreamingSink, including buffered component-opening handling.
crates/webui-handler/src/response_writer.rs New module providing append helpers and macros for defining/augmenting buffered writers.
crates/webui-handler/src/lib.rs Wires in the new module/exports, adds hidden trait methods, switches write_attr to call them, and adds a regression test.
crates/webui-handler/benches/streaming_hydration_bench.rs Adds macro-generated attribute methods to bench writer.
crates/webui-handler/benches/handler_bench.rs Adds macro-generated attribute methods to bench writer.
crates/webui-handler/benches/bootstrap_state_bench.rs Adds macro-generated attribute methods to bench writer.
crates/webui-ffi/src/lib.rs Replaces local string writer impl with macro-defined writer and updates construction callsite.
crates/webui-cli/src/commands/serve.rs Replaces local in-memory writer impl with macro-defined writer and adjusts ownership of output buffer.

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

Comment thread crates/webui-cli/src/commands/serve.rs Outdated
Move `use metafile::write_atomic;` into the contiguous import block so the
`define_string_response_writer!` invocation, which defines the `MemoryWriter`
type, sits after all imports instead of between them.

Addresses PR microsoft#467 review feedback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: bfb1dbef-d6a7-4d85-93c4-90d9b61cfc3c
@mohamedmansour
Mohamed Mansour (mohamedmansour) merged commit 39c263e into microsoft:main Aug 24, 2026
24 checks passed
@mohamedmansour
Mohamed Mansour (mohamedmansour) deleted the mohamedmansour-split-performance-prs branch August 24, 2026 19:15
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