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));
}
});
}
status
- the basic functionalities are complete
- API breakage can still happen
- some of the TODOs include additional tests, examples, and improvements to documentation