-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
switch to a more efficient vector/string representation #8981
Comments
I do not see the fact that we are heap-allocating some storage when making empty vectors as a drawback, at least not a serious one (assuming that empty vectors always have non-zero capacity). When I see an expression constructing an empty vector, I expect some elements to be pushed into it in the (near?) future, so we are just eagerly doing some work that we would do eventually anyway. (One exception to this that I could imagine would be a sparse collection backed by a vector of vectors, where most of its entries are empty.) |
The issue is that you don't have the option of creating an empty vector at all, without an extra branch on every operation (indexing, checking size, etc.) like you end up doing with Before:
After:
The allocation would just happen when you first push instead of at the declaration, so there wouldn't be no performance hit compared to the current situation. You always have the option of using |
@thestinger When you say "empty vector", you here mean "zero-capacity vector", right? (update: okay, a later revision to thestinger's comment makes it clear that is what he means.) |
@thestinger I understand your example, and it matches my understanding from when I wrote my original comment. When I wrote "empty vector", I mean zero-length vectors. I was trying to say "I do not see forcing non-zero-capacity on zero-length vectors as a drawback, because I expect zero-length vectors to be non-zero-length in the near future." (And then I noted one exception where I could see a case motivating support for zero-capacity vectors.) I guess all I was saying was that I wanted us to apply appropriate weights when doing a cost/benefit analysis of the change you are proposing. |
This is somewhat orthogonal to DST since we have already decided that there would be special representations for However, thinking on this a bit harder, if we could preserve the invariant that Given that restriction, I believe we are free to represent |
@pnkfelix I have written many functions that only sometimes need a vector, and sometimes don't. It's annoying to take the perf hit of heap allocation for the cases where I end up not needing the vector. A common case here is if I need to normalize data, but I want to avoid doing work in the case where the data is already normalized. |
There's no harm in doing the allocation at the first |
I updated the numbers based on the removal of jemalloc. They are likely much more platform-specific now. |
The consensus from today's meeting is that we should change the representation of owned vectors. We may possibly want to change the representation of slices as well, but that'll be an issue to tackle after this one. |
accepted for P-backcompat-lang for 1.0 |
Superseded by #11875. |
…nt_drop_lint, r=flip1995 Add details about how significant drop in match scrutinees can cause deadlocks Adds more details about how a significant drop in a match scrutinee can cause a deadlock and include link to documentation. changelog: Add more details to significant drop lint to explicitly show how temporaries in match scrutinees can cause deadlocks.
They are currently represented them as
*{ length, capacity, data[] }
. It means we have to handle trickieruint
overflow cases, which increases cost size a fair bit. It also means even an empty vector always requires a heap allocation.C++ represents a vector as
{ length, capacity, *data }
, so a fresh empty vector simply as anull
data pointer. Unlike theOptVec
optimization, it does not require an extra branch in every method. Callingrealloc
on a null pointer is well-defined, so you can ignore the special case.This has the drawback of making a move involve a 3-word copy, not 1-word. However, passing around unique vectors by-move rather than slices is not common enough to be a very relevant performance issue.
Benchmarks on x86_64 Linux (linux 3.11.5, glibc 2.18):
size_of::<uint>
3 * size_of::<uint>
2 * size_of::<uint>
2 * size_of::<uint> + 4 * size_of::<T>
4 * size_of::<T>
Note that since jemalloc is very clever, at some sizes preallocating has next to no advantage for the new proposed vector too.
Implementation:
The text was updated successfully, but these errors were encountered: