Skip to content

perf/fix: retain mut algorithm - #519

Open
fereidani wants to merge 1 commit into
servo:v2from
fereidani:v2_retain
Open

perf/fix: retain mut algorithm#519
fereidani wants to merge 1 commit into
servo:v2from
fereidani:v2_retain

Conversation

@fereidani

Copy link
Copy Markdown
Contributor

Closes #444

  • fixes panic behavior to match rust standard library
  • improves performance of retain algorithm by reducing memory copies

benchmark results shows about 20-30% performance improvement in cases that retain actually happens:

     Running benches/bench.rs (target/release/build/smallvec/5ddccd3aae9f1495/out/bench-5ddccd3aae9f1495)
bench_retain_mut_half   time:   [70.053 ns 70.416 ns 70.873 ns]
                        change: [-31.072% -29.765% -28.409%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe

bench_retain_mut_half_small
                        time:   [34.183 ns 34.212 ns 34.242 ns]
                        change: [+0.8531% +1.0178% +1.1919%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe

bench_retain_mut_all    time:   [27.246 ns 27.261 ns 27.277 ns]
                        change: [-5.8022% -3.9459% -2.4634%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  2 (2.00%) high severe

bench_retain_mut_all_small
                        time:   [27.199 ns 27.233 ns 27.275 ns]
                        change: [+1.4440% +2.2589% +3.1175%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 22 outliers among 100 measurements (22.00%)
  4 (4.00%) high mild
  18 (18.00%) high severe

bench_retain_mut_none   time:   [27.183 ns 27.202 ns 27.221 ns]
                        change: [-0.6473% -0.2981% +0.0314%] (p = 0.09 > 0.05)
                        No change in performance detected.
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) high mild

bench_retain_mut_none_small
                        time:   [27.180 ns 27.199 ns 27.217 ns]
                        change: [-4.1071% -2.2619% -0.7299%] (p = 0.00 < 0.05)
                        Change within noise threshold.

bench_retain_mut_vec_half
                        time:   [59.931 ns 60.049 ns 60.181 ns]
                        change: [-19.577% -19.106% -18.723%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) high mild

bench_retain_mut_vec_half_small
                        time:   [28.589 ns 28.622 ns 28.662 ns]
                        change: [-3.1025% -2.1240% -1.2223%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe

bench_retain_mut_vec_all
                        time:   [25.772 ns 25.800 ns 25.827 ns]
                        change: [+0.5852% +0.7517% +0.9227%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 8 outliers among 100 measurements (8.00%)
  1 (1.00%) low mild
  4 (4.00%) high mild
  3 (3.00%) high severe

bench_retain_mut_vec_all_small
                        time:   [25.933 ns 25.965 ns 26.005 ns]
                        change: [+0.8062% +0.9226% +1.0388%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

bench_retain_mut_vec_none
                        time:   [25.625 ns 25.637 ns 25.651 ns]
                        change: [-1.8376% -1.7440% -1.6515%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

bench_retain_mut_vec_none_small
                        time:   [25.897 ns 25.922 ns 25.948 ns]
                        change: [-0.2309% -0.0278% +0.2089%] (p = 0.82 > 0.05)
                        No change in performance detected.
Found 6 outliers among 100 measurements (6.00%)
  2 (2.00%) low mild
  1 (1.00%) high mild
  3 (3.00%) high severe

* fixes panic behavior to rust standard library
* improves performance of retain algorithm by reducing memory copies
@alejandro-vaz

Copy link
Copy Markdown
Collaborator

yeah improvements are crazy

Comment thread src/lib.rs
Comment thread src/lib.rs
original_len
};
// SAFETY: previous `read` is always less than original_len.
unsafe { drop_in_place(&mut *g.v.as_mut_ptr().add(read)) };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use the method instead here??

unsafe { g.v.as_mut_ptr().add(read).drop_in_place() }

codegen is probably the same but it avoids dereferencing and lets the machinery do whatever it needs to do

@alejandro-vaz alejandro-vaz Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or does codegen see something because it sees it's not a null pointer??

it shouldn't

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or why not even

unsafe { drop_in_place(g.v.as_mut_ptr().add(read)) };

@alejandro-vaz

alejandro-vaz commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

the only downside is that the algorithm is significantly more complex but it is worthwhile

I'll re-review this tomorrow, these hours are not a good time to be reasoning about unsafe rust, but it looks good

@alejandro-vaz

alejandro-vaz commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

@TDecking what are your thoughts on this

@TDecking TDecking 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.

This PR is a port of a std::Vec::retain_mut change done several month earlier. It should be fine to include.

Comment thread src/lib.rs
Comment on lines +1828 to +1830
// SAFETY: `read` is always less than original_len.
let ptr = g.v.as_mut_ptr();
let cur = unsafe { &mut *ptr.add(g.read) };

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.

This change from the main Rust implementation separated the safety comment from the unsafe block. Please fix it.

Comment thread src/lib.rs
// This drop guard will be invoked when predicate or `drop` of element
// panicked. It shifts unchecked elements to cover holes and
// `set_len` to the correct length. In cases when predicate and
// `drop` never panick, it will be optimized out.

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.

Suggested change
// `drop` never panick, it will be optimized out.
// `drop` never panics, it will be optimized out.

It also inside the main Rust repository.

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.

fix retain_mut panic/drop behavior to match vec API

3 participants