Skip to content

Delegate heap from_elem construction to Vec - #9

Open
charliermarsh wants to merge 2 commits into
v2from
charlie/codex-v2-fill
Open

Delegate heap from_elem construction to Vec#9
charliermarsh wants to merge 2 commits into
v2from
charlie/codex-v2-fill

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Sep 8, 2026

Copy link
Copy Markdown
Member

We currently construct spilled from_elem values through iterator extension. This change uses Vec's fill implementation when specialization is disabled and transfers the allocation into SmallVec. The existing specialized constructor is retained when that feature is enabled.

The inline constructor and generic Clone behavior are preserved. Regression tests cover capacity boundaries, zero-sized elements, clone counts, and cleanup after a cloning panic. Stable and all-features tests, Clippy, focused Miri in both modes, and the Rust 1.86 library check pass.

The committed benchmark harness is applied unchanged to the base and head for the measurements below.

Benchmarks

Performance depends on the filled value and size. Without specialization, 64 zero-valued u64s take 102.8–113.7% more time (+30.6–32.4 ns); nine zero bytes take 30.4–32.9% more time, and 1024 zero bytes take 18.7–20.8% more time. Nonzero byte fills improve by 52.0–53.8% at length 64 and 57.0–57.6% at length 1024; 64 false values improve by 65.3–65.4%.

The unchanged inline length-8 constructor measures about 0.32–0.35 ns slower on stable. The unchanged stable Vec controls vary from -1.9% to +0.0% for the nonzero length-64 fill and -0.5% to +10.6% for the zero length-1024 fill, so small shifts should not be treated as demonstrated improvements.

The retained specialized constructor has substantial variation in one run: the first pair measures 64-byte fills 57.0–67.9% slower while the unchanged Vec length-64 control is 70.2% slower. Those fills range from -1.3% to +3.2% in the other two pairs, with the Vec control from -1.2% to +0.9%. All runs are included below; this shared shift limits conclusions about specialized performance.

Stable Rust 1.98.1 uses bytes; nightly Rust 1.100.0 uses bytes,specialization. All constructors use inline capacity 8, and each timed iteration includes construction and destruction. The String case also includes creating its input string. The specialized constructor is retained; it is measured as a control alongside unchanged Vec fills.

Base: 401358a from astral-sh/rust-smallvec branch v2, with the same committed benchmark harness and dependency lockfile applied to each revision. Base and head are freshly compiled in separate target directories. AMD EPYC-Milan, x86_64 Linux, CPU 0; opt-level 3, fat LTO, one codegen unit. Criterion 0.8.2 uses 100 samples, 0.5s warmup, 2s measurement, and 95% confidence intervals. Three paired runs alternate base/head, head/base, base/head; timed processes are serialized. Before/after values below are the second pair; change ranges span all three pairs. Negative changes mean less time.

Configuration / case Before ns (95% CI) After ns (95% CI) Change across 3 pairs
stable / from_elem/u8_19/9 18.19 [17.91, 18.54] 14.03 [14.00, 14.09] -22.8% to -17.0%
stable / from_elem/u8_19/64 27.16 [27.14, 27.19] 13.02 [13.01, 13.05] -53.8% to -52.0%
stable / from_elem/u8_19/1024 43.09 [43.01, 43.22] 18.51 [18.40, 18.62] -57.6% to -57.0%
stable / from_elem/u8_0/9 17.42 [17.42, 17.43] 22.87 [22.84, 22.91] +30.4% to +32.9%
stable / from_elem/u8_0/64 27.29 [27.25, 27.33] 24.59 [24.44, 24.72] -14.7% to -9.9%
stable / from_elem/u8_0/1024 43.16 [43.11, 43.22] 52.16 [51.99, 52.36] +18.7% to +20.8%
stable / from_elem/u64_0/64 29.80 [29.63, 29.95] 60.42 [60.16, 60.66] +102.8% to +113.7%
stable / from_elem/bool_false/64 68.51 [68.46, 68.58] 23.76 [23.74, 23.79] -65.4% to -65.3%
stable / from_elem/vec_19_control/64 13.35 [13.33, 13.38] 13.10 [13.08, 13.13] -1.9% to +0.0%
stable / from_elem/vec_0_control/1024 51.86 [51.55, 52.19] 51.60 [51.47, 51.77] -0.5% to +10.6%
nightly / from_elem/u8_19/64 13.60 [13.37, 13.97] 13.58 [13.52, 13.63] -0.3% to +57.0%
nightly / from_elem/u8_0/1024 18.71 [18.45, 18.99] 18.19 [18.07, 18.32] -2.8% to -0.0%
nightly / from_elem/vec_19_control/64 13.10 [13.08, 13.13] 13.22 [13.15, 13.29] -1.2% to +70.2%
nightly / from_elem/vec_0_control/1024 49.81 [49.75, 49.89] 50.69 [50.59, 50.80] -2.2% to +1.8%
Full benchmark matrix
Configuration / case Before ns (95% CI) After ns (95% CI) Change across 3 pairs
stable / from_elem/bool_false/64 68.51 [68.46, 68.58] 23.76 [23.74, 23.79] -65.4% to -65.3%
stable / from_elem/string/64 2318.88 [2316.38, 2322.03] 2272.85 [2270.08, 2275.67] -2.0% to -0.9%
stable / from_elem/u64_0/64 29.80 [29.63, 29.95] 60.42 [60.16, 60.66] +102.8% to +113.7%
stable / from_elem/u64_19/64 29.76 [29.60, 29.93] 27.18 [26.98, 27.41] -8.7% to -6.7%
stable / from_elem/u8_0/1024 43.16 [43.11, 43.22] 52.16 [51.99, 52.36] +18.7% to +20.8%
stable / from_elem/u8_0/64 27.29 [27.25, 27.33] 24.59 [24.44, 24.72] -14.7% to -9.9%
stable / from_elem/u8_0/7 10.23 [10.21, 10.25] 9.25 [8.96, 9.56] -9.6% to -7.0%
stable / from_elem/u8_0/8 7.93 [7.92, 7.95] 8.28 [8.27, 8.29] +4.1% to +4.4%
stable / from_elem/u8_0/9 17.42 [17.42, 17.43] 22.87 [22.84, 22.91] +30.4% to +32.9%
stable / from_elem/u8_19/1024 43.09 [43.01, 43.22] 18.51 [18.40, 18.62] -57.6% to -57.0%
stable / from_elem/u8_19/64 27.16 [27.14, 27.19] 13.02 [13.01, 13.05] -53.8% to -52.0%
stable / from_elem/u8_19/7 10.23 [10.21, 10.26] 9.20 [8.93, 9.50] -10.1% to -5.6%
stable / from_elem/u8_19/8 7.92 [7.91, 7.92] 8.25 [8.24, 8.26] +4.0% to +4.2%
stable / from_elem/u8_19/9 18.19 [17.91, 18.54] 14.03 [14.00, 14.09] -22.8% to -17.0%
stable / from_elem/vec_0_control/1024 51.86 [51.55, 52.19] 51.60 [51.47, 51.77] -0.5% to +10.6%
stable / from_elem/vec_19_control/64 13.35 [13.33, 13.38] 13.10 [13.08, 13.13] -1.9% to +0.0%
stable / from_elem/zst/64 1.58 [1.58, 1.58] 1.58 [1.58, 1.59] -0.8% to +0.1%
nightly / from_elem/bool_false/64 13.46 [13.42, 13.50] 13.36 [13.34, 13.38] -1.3% to +67.9%
nightly / from_elem/string/64 2379.80 [2359.80, 2400.15] 2273.66 [2269.49, 2277.83] -4.5% to +2.1%
nightly / from_elem/u64_0/64 22.27 [22.24, 22.31] 22.97 [22.62, 23.37] -2.6% to +3.6%
nightly / from_elem/u64_19/64 21.05 [20.88, 21.23] 20.69 [20.64, 20.74] -1.7% to +2.0%
nightly / from_elem/u8_0/1024 18.71 [18.45, 18.99] 18.19 [18.07, 18.32] -2.8% to -0.0%
nightly / from_elem/u8_0/64 13.40 [13.37, 13.43] 13.45 [13.41, 13.49] +0.4% to +63.7%
nightly / from_elem/u8_0/7 9.89 [9.86, 9.92] 9.82 [9.81, 9.83] -0.7% to +0.3%
nightly / from_elem/u8_0/8 4.12 [4.12, 4.12] 4.12 [4.12, 4.12] -0.2% to +0.1%
nightly / from_elem/u8_0/9 14.03 [13.99, 14.07] 13.94 [13.94, 13.95] -2.7% to -0.6%
nightly / from_elem/u8_19/1024 19.04 [18.71, 19.44] 18.25 [18.12, 18.39] -4.1% to +3.3%
nightly / from_elem/u8_19/64 13.60 [13.37, 13.97] 13.58 [13.52, 13.63] -0.3% to +57.0%
nightly / from_elem/u8_19/7 9.85 [9.83, 9.88] 9.82 [9.81, 9.82] -0.3% to -0.2%
nightly / from_elem/u8_19/8 4.19 [4.12, 4.29] 4.14 [4.13, 4.15] -1.2% to +0.8%
nightly / from_elem/u8_19/9 14.72 [14.53, 14.97] 14.28 [14.28, 14.30] -3.0% to +2.3%
nightly / from_elem/vec_0_control/1024 49.81 [49.75, 49.89] 50.69 [50.59, 50.80] -2.2% to +1.8%
nightly / from_elem/vec_19_control/64 13.10 [13.08, 13.13] 13.22 [13.15, 13.29] -1.2% to +70.2%
nightly / from_elem/zst/64 1.58 [1.58, 1.58] 1.59 [1.59, 1.59] +0.5% to +0.8%

@charliermarsh charliermarsh changed the title Optimize repeated element and byte fills Delegate heap from_elem construction to Vec Sep 8, 2026
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