Skip to content

Reduce transport allocation and client hot-path overhead#196

Draft
Alek99 wants to merge 3 commits into
mainfrom
agent/transport-quick-wins
Draft

Reduce transport allocation and client hot-path overhead#196
Alek99 wants to merge 3 commits into
mainfrom
agent/transport-quick-wins

Conversation

@Alek99

@Alek99 Alek99 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Closes #176

Summary

Completes the transport-audit grab-bag with measured, independently reviewed changes across Python encoding, host framing, browser upload/draw paths, and reporting. The two proposed alternatives that did not preserve behavior or latency are retained as documented non-wins rather than shipped optimizations.

Disposition of every audit item

# finding disposition
1 split-mode ship_u8 padding copy Implemented. Split buffers contain only meaningful u8 bytes; packed layout retains alignment.
2 N-row constant area/error-band baseline Implemented. Scalar area baselines avoid canonical and wire arrays; constant array/error-band lowers retain public canonical data but use scalar wire encoding. Linear/log autorange, direct/decimated tiers, smooth/step, browser, SVG, and raster paths are covered.
3 direct_rgba full-size temporaries Implemented. Packing uses bounded scratch/output operations.
4 rect midpoint and stacked geometry temporaries Implemented. One midpoint temporary and shared stacked category geometry replace repeated full arrays.
5 hexbin center min/max rescan Implemented. Existing center-column zone maps feed ship; a regression makes any fallback min_max scan fail.
6 datetime ingest’s two copies Implemented. ABI 38 fuses native-endian fixed-duration W…as ticks into one f64-ms output, including strided/reversed/unaligned views, NaT, negative flooring, overflow, and precision boundaries. Calendar and non-native-endian cases keep the NumPy oracle path.
7 memory_report full payload build Implemented. An exact counting writer skips geometry encoding and the packed blob/join. Claims are intentionally scoped: channel normalization/RGBA preparation may still allocate.
8 Reflex fresh payload per subscriber Owned by draft PR #189 / issue #163. This branch does not duplicate that cache/restyle work.
9 payload_asset double joins Implemented. XYBF parts are hashed and atomically written incrementally through a unique temporary.
10 notebook repr retains full document plus escaped copy Implemented. Standalone parts are escaped in bounded slices directly into the iframe repr; output is byte-identical. This is a peak-memory win, not a latency claim.
11 equal-size tier update reallocates GL storage Implemented. bufferSubData updates same-byte-size buffers; size changes keep the safe bufferData path.
12 style channels always pad to vec4 Implemented. Shared dense packing uploads 4/8/12/16 B per item for 1/2/3/4 dynamic channels; scalar artist alpha stays in a uniform. All affected shaders reconstruct the original semantic vec4.
13 append matching allocates toPrecision(12) strings Investigated; no safe win. Exact numeric, Math.fround, and f32-bit candidates changed identity boundaries or collided; parsed-decimal numeric keys retained string allocation and were slower. Production semantics remain unchanged, with counterexamples committed as oracles.
14 synchronous pick readback and density blend repicks Partly implemented, partly rejected. One four-byte result buffer is reused and color-only density continuations preserve the valid pick snapshot without masking the geometry-changing frame’s invalidation. Async PBO/fence readback added latency and cancellation state, so synchronous 1×1 readback remains. Draft PR #193 complements this with same-device-pixel hit/miss reuse.

Draft PR #194 separately handles client hexbin fan instancing; it complements, but does not substitute for, item 5 here.

Performance evidence

Fresh reproducible local measurements, optimized versus the prior path:

scenario result
split u8, 100,001 values 100,004 → 100,001 B; 0.013 → 0.009 ms
scalar area, 200k build 0.413 → 0.248 ms; peak 1,610,264 → 8,272 B; canonical 4.8 → 3.2 MB
scalar area, direct 10k wire 120 → 80 KB
direct RGBA, 100k peak 7.309 → 4.575 MB; 1.014 → 0.976 ms
stacked bars, 8×100k peak 43.169 → 25.634 MB; 102.933 → 95.599 ms
hexbin centers, 18,890 0.0307 → 0.0208 ms
datetime, 1M ms / s / ns 0.244→0.146 / 0.748→0.365 / 0.731→0.487 ms; exact parity
memory report, plain 100k peak 1,607,311 → 303,786 B
memory report, channel-rich 100k peak 4,571,986 → 3,772,978 B; 0.442 → 0.405 ms; exact 1.6 MB count
notebook repr, 10k line peak 3,228,856 → 1,520,627 B (52.9% lower); 1.027 → 1.106 ms, hence memory-only claim
8 MB Reflex asset peak 8.134 → 0.132 MB; 3.862 → 3.541 ms
one style channel, 1M 16 → 4 MB; build/upload 2.6 → 1.5 ms

Rejected append-key alternatives

On 200,000 offset-encoded epoch values (base 1700000000000, step 1024, differing offsets), both Math.fround and reusable f32-bit keys collapsed 200,000 legacy identities into only 1,563 keys, produced 198,437 collisions, and mapped only 1,563 rows to the correct old index. Even the base and base+1024 collided. Legacy decimal keys remained 200,000/200,000 unique and correct. Parsing the same decimal strings into numeric Map keys preserved identity but was slower (41.5 vs 36.6 ms), so no production change is justified.

Rejected asynchronous picking

A clean synchronous 1×1 read measured at or below 0.1 ms. Dirty cost came from the required point redraw: 23.0 ms at 250k and 98.7 ms at 1M. The PBO/fence prototype completed its first result in about 4.0 ms and was unavailable in the first task in 13/14 trials, which would add tooltip latency and cancellation complexity. The branch instead removes needless dirty frames and reuses the result allocation.

Verification

Final exact integrated tree:

  • complete suite: 2250 passed, 66 skipped, 1 deselected, 3 warnings in 76.36 s
  • integrated production-bundle real-Chromium regressions: 5 passed
  • reviewer-focused host/Python suite: 349 passed
  • browser/export follow-up: 66 passed
  • benchmark contract tests: 6 passed
  • Rust library: 103 passed
  • ABI smoke: 125 checks passed
  • node js/build.mjs --check: committed bundles fresh
  • tsc -p js/tsconfig.json --noEmit: passed
  • Ruff check/format: passed
  • rustfmt check: passed
  • git diff --check: passed

The one deselection is tests/reflex_adapter/test_assets.py::test_client_source_is_the_installed_bundle. This branch leaves that test byte-for-byte equal to main; run alone, it reproduces the known stale assertion that searches minified Vite output for unmangled source spellings. Its semantic export-marker correction remains scoped to draft PR #189.

Reproducible client profiling is committed as benchmarks/bench_client_transport_quick_wins.py; backend microbench contracts are committed in benchmarks/test_codspeed_kernels.py.

@codspeed-hq

codspeed-hq Bot commented Jul 22, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 32.74%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 96 untouched benchmarks
🆕 6 new benchmarks
⏩ 1 skipped benchmark1

Performance Changes

Benchmark BASE HEAD Efficiency
test_first_payload_area_core_2d 9.5 ms 7.2 ms +32.74%
🆕 test_datetime_seconds_fused_one_copy_ingest N/A 3.1 ms N/A
🆕 test_first_payload_scatter_direct_rgba N/A 12.1 ms N/A
🆕 test_first_payload_stacked_bar_reuses_category_geometry N/A 430.7 ms N/A
🆕 test_hexbin_payload_reuses_precomputed_center_bounds N/A 960.3 µs N/A
🆕 test_memory_report_counts_without_payload_blob N/A 7.4 ms N/A
🆕 test_notebook_repr_line_streams_escaped_document N/A 11.9 ms N/A

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing agent/transport-quick-wins (6e96a70) with main (2a7d898)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR reduces transport and rendering hot-path allocations. The main changes are:

  • Compact wire encoding for scalar baselines and split byte columns.
  • Fused native conversion for fixed-unit NumPy datetimes.
  • Incremental payload accounting, asset writing, and notebook escaping.
  • Dense WebGL style channels and same-size GPU buffer updates.
  • Reduced temporary geometry and color allocations.
  • Focused performance and behavior tests.

Confidence Score: 5/5

This looks safe to merge.

No blocking issues found in the changed code.

T-Rex T-Rex Logs

What T-Rex did

  • The runtime probe reported style buffers of 8 and 32 bytes with correct rendered alpha, and observed 1/2/3/4-channel reused allocations of 28/56/84/112 bytes, confirming memory and rendering behavior.
  • The Tier probe reported all contracts true, including sameSizeUsedSubData, changedSizeReallocated, resizedStorageThenReused, identitiesStable, and trackedSizesExact.
  • Before-change production bundle failed the new style-packing contracts while the after-change bundle passed, with comparable real-bundle render recordings included.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
python/xy/columns.py Adds fused fixed-unit datetime conversion while retaining NumPy fallbacks for unsupported units.
src/lib.rs Adds the native datetime conversion ABI with stride, NaT, flooring, and overflow handling.
python/xy/_payload.py Adds scalar baseline encoding and allocation-light payload byte counting.
python/reflex-xy/reflex_xy/payload_asset.py Hashes and writes frame parts incrementally through unique atomic temporary files.
js/src/50_chartview.ts Adds compact instance-style buffers, same-size GPU updates, reusable pick storage, and refined pick invalidation.
js/src/40_gl.ts Reconstructs semantic style vectors from compact attributes and uniform defaults.
python/xy/export.py Streams escaped standalone content into notebook iframe output to reduce peak memory.

Reviews (1): Last reviewed commit: "Optimize client transport hot paths" | Re-trigger Greptile

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.

Grab-bag of small copy/byte cleanups from the transport audit

1 participant