Cloning a Vec<String> significantly slower compared to C++?
I am not very proficient in C++, but while attempting a comparison benchmark I came across an interesting result - cloning a vector of strings is significantly slower (between x5 and x10, depending on the platform tested) in Rust compared to C++.
I'm using the following code in C++ to clone the strings:
void foo(vector<string> strings) {
auto start = high_resolution_clock::now(); // Start time
for (int i = 0; i < 1000; ++i) {
vector<string> temp(strings);
if (strings[0].c_str() == temp[0].c_str()) {
abort();
}
}
auto end = high_resolution_clock::now(); // End time
auto duration =
duration_cast<microseconds>(end - start) / 1000;
cout << "Time taken for each iteration: " << duration.count() << " micros"
<< endl;
}
and this code for Rust:
fn foo(strings: Vec<String>) {
let start = Instant::now(); // Start time
for _ in 0..1000 {
let _unused = strings.clone();
}
let duration = start.elapsed(); // Calculate duration
println!("Time for iteration: {} micros", duration.as_micros() / 1000);
}
Running both with the contents of /usr/share/dict/words (235976 strings of varying sizes) yields very bad results for Rust. For example on my Intel Ubuntu, using g++ 11.4 and x86\_64, Rust clocks in at around 10ms, while C++ gets 1.8ms...
Does anybody have any idea where this difference can stem from? I also tried swapping my allocator for jemalloc but I'm getting similar differences
EDIT: I made sure that in the C++ implementation the strings actually get copied (i.e. c\_str() returns different addresses for the same element after the copy)
EDIT 2: Yes, I ran the rust code with --release, and the C++ code with -O3
EDIT 3: No, it is not a reasonable assumption that the compiler optimizes away the allocation. Even if that were the case - the loop time should have been zero microseconds and not 1000-10000 as it is in reality
EDIT 4: Thanks a lot for the help! As several commenters observed, C++ strings have the small string optimization implemented by default, so reading from /usr/share/dict/words gives it an unfair advantage. Switching the test to long arbitrary strings changed it, and I now get either comparable results, or a clear advantage for Rust, depending on the platform I test