After executing this:
use std::sync::Arc;
use std::time::Instant;
fn main() {
let cap = 100000000;
let b0 = vec![0; cap];
let now = Instant::now();
Arc::new(b0);
println!("T0: {:?}", now.elapsed());
let c0 = vec![0; cap];
let _ = c0.clone(); // <- this makes it slow
let now = Instant::now();
Arc::new(c0);
println!("T1: {:?}", now.elapsed());
}
The result is: T0: 5.971µs T1: 26.69574ms
Why the second Arc::new is slow if we clone c0 before?
Edit:
I tested it with:
T1's time increases linearly with the vector size.
Note that you are not measuring the time taken by the Arc::new
, but instead you are measuring the time taken when the Arc is dropped (since you don't assign it to anything).
Note also that depending on your system, this line:
let b0 = vec![0; cap];
may not allocate any physical memory: it can allocate only virtual space, with the physical memory being allocated and zeroed on the first time it is accessed. This is confirmed by cachegrind that shows almost no cache misses until the buffer is cloned.
Cloning the vector has two side effects:
Arc
,Using the following code, which moves the deallocation out of the measured timings, the times are much faster and closer:
use std::sync::Arc;
use std::time::Instant;
fn main() {
let cap = 1000000000;
let b0 = vec![0; cap];
let now = Instant::now();
let a = Arc::new(b0);
println!("T0: {:?}", now.elapsed());
drop (a);
let c0 = vec![0; cap];
let _ = c0.clone(); // <- this makes it slow
let now2 = Instant::now();
let a = Arc::new(c0);
println!("T1: {:?}", now2.elapsed());
drop (a);
}
The second Arc::new
is still slower, but the difference can be explained by the 3 extra L3-cache misses reported by cachegrind.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With