-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use a union to reduce the size of SmallVec [v2] #94
Conversation
☔ The latest upstream changes (presumably #97) made this pull request unmergeable. Please resolve the merge conflicts. |
I rebased on master now, the only change I kept was to add the return type to remove_no_inline (to prevent over optimization, specially for Vec). |
lib.rs
Outdated
//! Note that `smallvec` can still be larger than `Vec` if the inline buffer is larger than two | ||
//! machine words. | ||
//! | ||
//! To use this feature add `features = ["uuid"]` in the `smallvec` section of Cargo.toml. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be union
instead of uuid
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ops, will fix.
It'd be nice to get this moving. It may be interesting for rustc as well. |
@mbrubeck Do you have time to review these changes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great, thanks! Some requests/suggestions below.
Cargo.toml
Outdated
default = ["std"] | ||
|
||
[lib] | ||
name = "smallvec" | ||
path = "lib.rs" | ||
|
||
[dependencies] | ||
unreachable = "1.0.0" | ||
debug_unreachable = "0.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may not want to use debug_unreachable
, because it is unmaintained and doesn't work correctly in Rust > 1.0: reem/rust-debug-unreachable#6
We could just use unreachable
all the time, or write our own debug_unreachable
macro, or write a new debug_unreachable
-like crate...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I'll remove the dependency and add the equivalent macro.
@@ -350,14 +419,25 @@ impl<A: Array> SmallVec<A> { | |||
/// ``` | |||
#[inline] | |||
pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> { | |||
let (ptr, cap, len) = (vec.as_mut_ptr(), vec.capacity(), vec.len()); | |||
mem::forget(vec); | |||
if vec.capacity() <= A::size() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation says that from_vec
does not copy the elements. I think we should keep the current behavior of keeping the items on the heap. Users who want to move them inline if possible can use shrink_to_fit
or other methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unfortunately not possible with the new design: there is no way of representing a heap-allocated buffer with a capacity less than A::size()
. If self.capacity <= A::size()
then the code assumes that the data is in the inline buffer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right. In that case the documentation should be updated.
lib.rs
Outdated
@@ -301,7 +370,7 @@ impl<A: Array> Drop for SmallVecData<A> { | |||
/// assert!(v.spilled()); | |||
/// ``` | |||
pub struct SmallVec<A: Array> { | |||
len: usize, | |||
capacity: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using capacity
here is a little confusing to me, but I'm not sure what a better name would be. Maybe something like len_cap
? Maybe capacity
is okay, but there should be a comment here describing the semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
lib.rs
Outdated
} | ||
|
||
#[inline] | ||
fn triple(&self) -> (*const A::Item, usize, usize) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment to say what the return value means.
lib.rs
Outdated
while len < *len_ptr { | ||
let last_index = *len_ptr - 1; | ||
*len_ptr = last_index; | ||
ptr::read(ptr.offset(last_index as isize)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use ptr::drop_in_place
instead of ptr::read
.
lib.rs
Outdated
} else { | ||
let ptr = self.as_ptr(); | ||
for i in 0..self.len() { | ||
ptr::read(ptr.offset(i as isize)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use ptr::drop_in_place
instead.
Great, thanks! I think this is ready but I just want to double-check all the unsafe code before merging it (and give a chance for others to do the same). |
@bors-servo r+ |
📌 Commit cfa1f0c has been approved by |
Use a union to reduce the size of SmallVec [v2] Building on top of #92 by @Amanieu I introduced `triple()` and `triple_mut()` which removed almost all of the runtime overhead. Performance is very comparable. ``` name master:: ns/iter union:: ns/iter diff ns/iter diff % speedup bench_extend 45 47 2 4.44% x 0.96 bench_extend_from_slice 45 43 -2 -4.44% x 1.05 bench_from_slice 45 44 -1 -2.22% x 1.02 bench_insert 615 622 7 1.14% x 0.99 bench_insert_from_slice 101 99 -2 -1.98% x 1.02 bench_insert_many 309 266 -43 -13.92% x 1.16 bench_macro_from_elem 41 37 -4 -9.76% x 1.11 bench_macro_from_list 40 42 2 5.00% x 0.95 bench_push 381 370 -11 -2.89% x 1.03 bench_pushpop 404 420 16 3.96% x 0.96 bench_remove 458 436 -22 -4.80% x 1.05 ``` <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/94) <!-- Reviewable:end -->
☀️ Test successful - status-travis |
Changes in this release: * Fix possible double-free in `insert_many` when passed an iterator that panics in `next` (servo#103) * Add a new `union` feature (disabled by default) that reduces the size of the SmallVec struct (servo#94) * Improve performance of `extend` and `from_elem` (servo#93) * Improve performance of `drop` (servo#100) * Update dev-dependency on `bincode` (servo#102) * Update to build without `std` on current Rust nightly (servo#104) * Additional benchmarks (servo#95, servo#97).
Changes in this release: * Fix possible double-free in `insert_many` when passed an iterator that panics in `next` (servo#103) * Add a new `union` feature (disabled by default) that reduces the size of the SmallVec struct (servo#94) * Improve performance of `extend` and `from_elem` (servo#93) * Improve performance of `drop` (servo#100) * Update dev-dependency on `bincode` (servo#102) * Update to build without `std` on current Rust nightly (servo#104) * Additional benchmarks (servo#95, servo#97).
Version 0.6.3 Changes in this release: * Fix possible double-free in `insert_many` when passed an iterator that panics in `next` (#103) * Add a new `union` feature (disabled by default) that reduces the size of the SmallVec struct (#94) * Improve performance of `extend` and `from_elem` (#93) * Improve performance of `drop` (#100) * Update to build without `std` feature on current Rust nightly (#104) * Additional benchmarks (#95, #97) * Update dev-dependency on `bincode` (#102) <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/105) <!-- Reviewable:end -->
This is what the standard Vec does; see rust-lang/rust#32012.
Building on top of #92 by @Amanieu
I introduced
triple()
andtriple_mut()
which removed almost all of the runtime overhead. Performance is very comparable.This change is