On 04/04/14 10:51 AM, Manu Thambi wrote:
> 
>> Needing to use a header seriously hurts the performance. The new
>> vector is 7x faster at pushing elements when space isn't reserved
>> compared to the old one, all due to leaving off the length/capacity
>> header. The overhead would be less if it stored the capacity inside
>> *and* outside the vector, but it's still overhead. It's an extra
>> overflow check branch along with needing to calculate padding for
>> alignment in the future, extra space in the memory allocation and more
>> pointer aliasing issues. 
> Perhaps I am not understanding you correctly. Assuming that the capacity
> is stored inside and outside Vec, the only overhead
> I see is during allocation/deallocation. Otherwise the code will be
> identical.

It bloats the code size by requiring extra overflow checks in functions
like `push`, which impacts performance. Unwinding prevents many LLVM
passes from doing their job, since it adds significant complexity to the
control flow.

In addition to this, there is even an impact on the performance of
immutable operations like indexing. There's a need to calculate the
offset to the first element in the vector, which includes compensating
for alignment because there can be padding in between the capacity and
the first element in the vector.

You can deny that this has performance implications, but the fact is
that I have looked at the performance and code size impact in depth and
and have hard numbers from benchmarks proving that there is a enormous
performance overhead for this choice.

> If you are worried about space, there is a cost of
> passing around Vecs ( vs ~[T]), which consumes and extra register for
> the capacity.

Passing vectors around by-value isn't a common operation. In the common
case, functions operate on mutable or immutable borrowed slices. In
uncommon cases, they operator on `&mut Vec<T>` in order to change the
length in place. There are rare cases when ownership needs to be moved,
but it's rare for it not to correspond by a constant factor to the
number of allocations.

>> It's going to be forbidden from actually being null in the future when
>> the Option-like enum optimization is applied to it via an attribute.
>> This work has already landed - calling exchange_free on a zero-size
>> allocation is *forbidden*.
> As mentioned elsewhere on this thread, we can use another invalid
> pointer value to represent
> either Option-None or 0 capacity depending on which is more efficient.

I've already implemented support for this in the compiler some time ago
and the library portion is now in master. This means it's invalid to
call exchange_free on an allocation with a zero size capacity, so slices
need to track whether the allocation is zero size. A zero size length
does not imply a zero size capacity unless `Vec<T>` -> `~[T]` is not a
no-op, which is what I am saying. Commits:

1778b6361627c5894bf75ffecf427573af02d390
898669c4e203ae91e2048fb6c0f8591c867bccc6

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to