Change:
Benchmark program at the end. The results: That comes out to 300 MB/s… really bad for a memory copy. I'm guessing this has to do with the fact that is generic. Its looks like and LLVM probably isn't smart enough to optimize this down to a . But anyway, there is a need for efficient vectors of primitive numerical types. If this can't happen by optimization magic, we need something like (untested). I can also imagine a language feature which would let you write This is worryingly close to C++ template specialization, but might be worth it for core data structures. It's really counterintuitive if you need to use a special vector type or a special clone method to get acceptable performance on vectors of primitive integers. Bonus weirdness: If you comment out then gets significantly faster (though still way too slow): If you comment out instead, nothing in particular happens. Here's the benchmark program:
I think this is probably . I don't think we need to change any of the vector code, it's a fixable bug.
might also be related.
(Actually, I suppose I'd want and then is a one-liner using that.)
was renamed to , fwiw.
I'm looking into this (and the related bugs) and it seems that LLVM is suspicious of the write to the vector length during the copy loop and therefore doesn't convert the loop to a memcpy. I'm currently coaxing the relevant code to allow LLVM to optimise to a memcpy where it can.
What if you mark the pointer as ? It would be correct to have rustc mark all pointers to types without inside that way.
I think it might be more than that. The bounds checks seem to cause the memcpy recogniser to fail, even though they actually get optimised out anyway.
AFAIK, there are no bounds checks here. It may hit the issue causing a redundant null check to be in the loop due to a missed optimization in LLVM. That's caused by the lack of a way to tell LLVM a pointer is non-null, but I expect LLVM could do better even without it. I guess you mean the comparison of the length against the capacity in ?
(If we want to, we can also rewrite the vec code to use the intrinsic or whatever it's called)
Using will only fix a subset of this problem, because many types are not but still have a trivial implementation. The bug will still need to remain open if that's the attempted fix.
So I did the pragmatic thing and just made the code itself slightly better. There's no special-casing of types, so it's still fully general. I'm just making sure it still passes the tests now, but the benchmarks on my machine are: Both are done with just .

Discussion:
/// Returns a copy of `v`. #[inline] fn to_owned(&self) -> ~[T] { <del> let mut result = with_capacity(self.len()); for e in self.iter() { result.push((*e).clone()); </del> <ins> let len = self.len(); let mut result = with_capacity(len); // Unsafe code so this can be optimised to a memcpy (or something // similarly fast) when T is Copy. LLVM is easily confused, so any // extra operations during the loop can prevent this optimisation unsafe { let mut i = 0; let p = result.as_mut_ptr(); // Use try_finally here otherwise the write to length // inside the loop stops LLVM from optimising this. try_finally( &mut i, (), |i, ()| while *i < len { mem::move_val_init( &mut(*p.offset(*i as int)), self.unsafe_ref(*i).clone()); *i += 1; }, |i| result.set_len(*i)); </ins> } result }

impl<A: Clone> Clone for ~[A] { #[inline] fn clone(&self) -> ~[A] { <del> self.iter().map(|item| item.clone()).collect() </del> <ins> // Use the fast to_owned on &[A] for cloning self.as_slice().to_owned() </ins> } fn clone_from(&mut self, source: &~[A]) {

impl<T:Clone> Clone for Vec<T> { fn clone(&self) -> Vec<T> { <del> self.iter().map(|x| x.clone()).collect() </del> <ins> let len = self.len; let mut vector = Vec::with_capacity(len); // Unsafe code so this can be optimised to a memcpy (or something // similarly fast) when T is Copy. LLVM is easily confused, so any // extra operations during the loop can prevent this optimisation { let this_slice = self.as_slice(); while vector.len < len { unsafe { mem::move_val_init( vector.as_mut_slice().unsafe_mut_ref(vector.len), this_slice.unsafe_ref(vector.len).clone()); } vector.len += 1; } } vector </ins> } fn clone_from(&mut self, other: &Vec<T>) {