Why is std::sync::Mutex 60-70x time slower than C++'s std::mutex?
Partially solved: As people have speculated in the comments, it appears that C++ is indeed cheating. If we wrap the whole thing into a thread and join it at the end, we see the same performance: Rust C++
use std::sync::Mutex;
use std::time::Instant;
pub fn main() {
let mut mutexes = Vec::new();
for _ in 0..1_000_000 {
mutexes.push(Mutex::new(()))
}
let begin_time = Instant::now();
for mutex in &mutexes {
let _ = mutex.lock().unwrap();
}
let duration = begin_time.elapsed();
println!("{} us", duration.as_micros());
}
This code puts 1 million std::sync::Mutexes on the heap, locks and immediately unlocks them in a loop. With Rust 1.56.1 it takes around 15ms for the loop part (this is 30x instead of 60x slower because I made a mistake in code when I posted and I can't edit the title. See the edit note below).
$ rustc -C opt-level=3 mutex.rs
$ ./mutex
15288 us
The equivalent C++ code looks like this, using std::scoped_lock
#include <chrono>
#include <iostream>
#include <mutex>
#include <vector>
int main() {
std::vector<std::mutex> mutexes(1'000'000);
auto begin_time = std::chrono::high_resolution_clock::now();
for (auto &mutex : mutexes) {
std::scoped_lock<std::mutex> lock(mutex);
}
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = end_time - begin_time;
auto micros =
std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
std::cout << micros << " us" << std::endl;
return 0;
}
This takes only 450μs with Clang 10.0.0
$ clang++ -std=c++17 -O2 mutex.cpp
$ ./a.out
456 us
Note that neither compiler optimised out the mutex locks as we can see pthread_mutex_lock being called in both disassemblies: Rust C++. So we are indeed measuring the mutex
Edit: u/SkiFire13 noted in a comment that in a previous version of my code I moved mutexes vector into the iterator and hence was measuring the time to destruct the vector as well. I have changed the code to borrow it instead and it's now \~30x slower instead of 60x