Skip to content

perf: move Community batch writes onto dense native rows - #9

Closed
wolfiesch wants to merge 5 commits into
mainfrom
perf/community-dense-write-parity
Closed

perf: move Community batch writes onto dense native rows#9
wolfiesch wants to merge 5 commits into
mainfrom
perf/community-dense-write-parity

Conversation

@wolfiesch

@wolfiesch wolfiesch commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Moves the common Community append() / write_rows() batch path from per-cell nested BTreeMap insertion to compact native dense rows while retaining sparse last-write-wins overlays for later edits and formats.

The stale portion of the audit is corrected here: current Community already crosses PyO3 once per append/bulk buffer. This PR therefore claims removal of the native per-cell tree storage, not removal of per-cell FFI.

Implementation

  • stage each Python value/style grid once, then commit monotonic batches as contiguous native rows
  • retain the existing sparse path for non-monotonic writes
  • merge dense rows with sparse edits deterministically at emission
  • preserve dense values when a later format materializes an overlay
  • include dense cells in dimensions, calc chains, autofilter evaluation, and streaming-mode eligibility checks
  • validate grid bounds before mutating the worksheet
  • retain reproducible public-API and direct-Rust benchmark harnesses in the repository

Production-profile evidence

Evidence workflow: https://github.com/SynthGL/wolfxl-community/actions/runs/33599139211
Artifact: https://github.com/SynthGL/wolfxl-community/actions/runs/33599139211/artifacts/9834572130

Method:

  • exact base: cc624eabd6f65301ccc5d9adb24a6cb6b0d271d5
  • measured candidate production code: 5c6a31b888bdefd50c981703e9ab4fbe3626912b
  • both wheels built with fat LTO and one codegen unit
  • 25 alternating, isolated-process observations per public lane
  • 400,000 cells in each timing lane
  • median, p95, and coefficient of variation reported
  • three isolated peak-RSS observations on 600,000 unique strings
  • same-binary direct Rust sparse-vs-dense storage/emission allocation benchmark
  • fixed ZIP epoch and byte-for-byte archive comparison

Public Python API

lane phase before median after median change speedup p95 before/after CV before/after
append numeric save 132.112 ms 93.174 ms -29.5% 1.418× 162.376/97.534 ms 7.4%/2.3%
append numeric total 162.390 ms 119.485 ms -26.4% 1.359× 197.452/125.678 ms 7.5%/2.4%
append mixed save 162.512 ms 115.439 ms -29.0% 1.408× 175.593/128.472 ms 3.5%/4.1%
append mixed total 232.207 ms 177.136 ms -23.7% 1.311× 248.709/197.366 ms 3.3%/3.6%
write_rows numeric save 117.721 ms 77.914 ms -33.8% 1.511× 120.056/80.645 ms 2.0%/1.4%
write_rows numeric total 141.395 ms 97.045 ms -31.4% 1.457× 145.038/100.290 ms 2.0%/1.4%
write_rows unique strings save 194.676 ms 149.051 ms -23.4% 1.306× 214.598/152.604 ms 6.3%/2.0%
write_rows unique strings total 324.787 ms 270.984 ms -16.6% 1.199× 344.838/276.234 ms 5.5%/2.1%

The supported claim is therefore 1.31–1.51× faster save/flush and 1.20–1.46× faster end-to-end on the measured Community append/bulk lanes—not the audit's unmeasured 1.5–3× range.

Direct Rust phase and allocations

Sparse vs dense native storage plus sheetData emission, 400,000 numeric cells:

metric sparse dense change
median 56.334 ms 35.209 ms -37.5% / 1.600×
allocation calls 1,283,355 1,220,037 -4.9%
allocated bytes 140,439,918 92,136,494 -34.4%

Peak RSS

600,000 unique-string cells, three isolated samples per side:

  • before: 339,896 / 339,896 / 339,888 KiB
  • after: 265,116 / 264,992 / 264,984 KiB
  • median: 339,896 → 264,992 KiB (-22.0%)

Correctness and validation

The temporary benchmark workflow was removed after publishing the evidence artifact.

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.

1 participant