locktick

locktick provides the means to measure things like the average guard duration and wait time for different kinds of locks, just by substituting the applicable locks' imports.
It makes the detection of deadlocks trivial, and can point to all the locks involved.
Example use
use std::{thread, time::Duration};
use locktick::lock_snapshots;
fn print_active_guards() {
thread::spawn(|| {
loop {
let mut locks = lock_snapshots();
locks.sort_unstable_by(|l1, l2| l1.location.cmp(&l2.location));
if locks.iter().flat_map(|lock| lock.known_guards.values()).all(|g| g.num_active_uses() == 0) {
println!("there are no active guards");
} else {
println!("\nthere are active guards:");
for lock in locks {
let mut active_guards = lock.known_guards.values().filter(|g| g.num_active_uses() != 0).collect::<Vec<_>>();
if active_guards.is_empty() {
continue;
}
active_guards.sort_unstable_by(|g1, g2| g1.location.cmp(&g2.location));
println!("{}:", lock.location);
for guard in &active_guards {
let location = &guard.location;
let kind = guard.kind;
let num_uses = guard.num_uses;
let avg_duration = guard.avg_duration();
let avg_wait_time = guard.avg_wait_time();
println!(
"- {location} ({:?}): used {num_uses} time(s) so far; avg duration: {:?}; avg wait: {:?}",
kind, avg_duration, avg_wait_time
);
}
}
}
thread::sleep(Duration::from_secs(1));
}
});
}
crate features
std (default): wrappers for the std::sync Mutex and RwLock
parking_lot: wrappers for the parking_lot Mutex and RwLock
tokio: wrappers for the tokio::sync Mutex and RwLock
tracing: emits TRACE-level logs related to the tracked guards
status
- the basic functionalities are complete
- API breakage can still happen
- some of the TODOs include additional tests, examples, and improvements to documentation