Repository navigation
Conversation
An experiment showing what PRs #61 (reader) and #62 (writer) gain together, with the reader built on buffa's proposed `packed_views` (anthropics/buffa#814) instead of a hand-written wire scanner. buffa comes from the `packed-views` branch of nyurik/buffa through `[patch.crates-io]` until that change is released, so this branch is not for merging as is. **What's here** - **Reader, on buffa views:** `examples/codegen.rs` sets `packed_views(true)`, so `FeatureView.tags` and `.geometry` are borrowed `PackedView`s instead of a `Vec` each. That's the allocation PR 61 removes with its 745-line `src/reader/wire.rs`; here buffa does it, and `wire.rs` isn't needed. - **PR 61's geometry parser:** `src/geom_reader.rs` is PR 61's, unchanged. It parses straight from the packed varints (no temporary vectors, rings sized once) and takes buffa's iterator as is. - **Layer values resolved once:** each layer's values become `MvtValueRef`s once in `MvtReaderRef::new`, instead of being matched from the `ValueView` on every property. PR 61 does the same. - **PR 62's writer:** `src/writer.rs` is PR 62's, unchanged. It orders values by index, predicts tag keys, boxes and reuses layer state, packs varints in one pass, and writes layers straight into the tile buffer. - **API:** `MvtFeatureRef::tags()` and `geometry_commands()` return `ExactSizeIterator<Item = u32>` instead of slices. That's a breaking change, as PR 61's `generate_views(false)` also is. `Debug` output is unchanged. **Results:** measured on dedicated AWS hosts over the 207 real-world fixtures, for the reader and writer parts separately before they were combined here. x86 is c8a.large; ARM is c8g.large. | | main | this branch | PR 61 / PR 62 alone | |---|---:|---:|---:| | `MvtReaderRef::new`, x86 instructions | 1,221 M | 551 M | 526 M | | full traversal, x86 instructions | 1,925 M | 1,516 M | 1,385 M | | full traversal, x86 time | 134.6 ms | 95.2 ms | 85.3 ms | | full traversal, ARM time | 190.9 ms | 129.8 ms | 113.4 ms | | criterion decode, x86 | 49.6 ms | 37.7 ms | 29.6 ms | | allocations, full traversal | 1,489,555 | 347,383 | 338,383 | | reader heap per tile byte | 6.26 B | 5.38 B | 1.82 B | | `encode_ref`, x86 instructions | 2,551 M | 1,790 M (PR 62) | 1,790 M | | criterion encode, x86 | 4.27 ms | 3.10 ms (PR 62) | 3.10 ms | - **Decoding alone** matches PR 61. - **Full traversal** is 10–12% behind PR 61, which keeps a few offsets per feature where buffa keeps a full view struct. - **Encoding** is PR 62's. - **Output:** every tile encodes byte-identically to v0.7.1, for `encode_ref` and the streaming builder. All 338 tests pass, including the 212 fixture snapshots; clippy is clean, and the codegen example reproduces the checked-in generated code. The geometry parser and the writer are AnthonyKrupko's work from #61 and #62. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy/paste detectionℹ️ Found 3 clones (0 new compared to Clones
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #66 +/- ##
==========================================
+ Coverage 99.20% 99.27% +0.06%
==========================================
Files 11 11
Lines 2018 2073 +55
==========================================
+ Hits 2002 2058 +56
+ Misses 16 15 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
fast-mvt encode/decode — CPU instruction countsfast-mvt's own encode/decode instruction counts, measured by gungraun under Valgrind/Callgrind — one-shot and deterministic, so these are exact (the Results |
|
I think I found one inefficiency in buffa as well, I'll double check it and get it to your buffa pr as a comment, it reduces the gap between this PR and 61/62 by a large margin |
|
I profiled this branch against #61 to see where the reader loses time. On reading every feature of the 207 real-world tiles (Callgrind instructions, measured pass only), it was 21% behind #61:
Most of the gap was
One small thing on this branch: #61 gave #62 doesn't depend on any of this: |
An experiment showing what PRs #61 (reader) and #62 (writer) gain together, with the reader built on buffa's proposed
packed_views(anthropics/buffa#814) instead of a hand-written wire scanner. buffa comes from thepacked-viewsbranch of nyurik/buffa through[patch.crates-io]until that change is released, so this branch is not for merging as is.What's here
examples/codegen.rssetspacked_views(true), soFeatureView.tagsand.geometryare borrowedPackedViews instead of aVeceach. That's the allocation PR 61 removes with its 745-linesrc/reader/wire.rs; here buffa does it, andwire.rsisn't needed.src/geom_reader.rsis PR 61's, unchanged. It parses straight from the packed varints (no temporary vectors, rings sized once) and takes buffa's iterator as is.MvtValueRefs once inMvtReaderRef::new, instead of being matched from theValueViewon every property. PR 61 does the same.src/writer.rsis PR 62's, unchanged. It orders values by index, predicts tag keys, boxes and reuses layer state, packs varints in one pass, and writes layers straight into the tile buffer.MvtFeatureRef::tags()andgeometry_commands()returnExactSizeIterator<Item = u32>instead of slices. That's a breaking change, as PR 61'sgenerate_views(false)also is.Debugoutput is unchanged.Results: measured on dedicated AWS hosts over the 207 real-world fixtures, for the reader and writer parts separately before they were combined here. x86 is c8a.large; ARM is c8g.large.
MvtReaderRef::new, x86 instructionsencode_refand the streaming builder.All 338 tests pass, including the 212 fixture snapshots; clippy is clean, and the codegen example reproduces the checked-in generated code. The geometry parser and the writer are @AnthonyKrupko's work from #61 and #62.