locks: add process-wide lock hold time tracking
TrackedMutex and TrackedRwLock wrappers that record hold durations by source location using #[track_caller]. Stats written to ~/.consciousness/lock-stats.json every second, sorted by max hold time. Re-exported as crate::Mutex so all locks are instrumented. To disable, swap the re-export back to tokio::sync::Mutex. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
b94e056372
commit
f56fc3a7c7
9 changed files with 286 additions and 17 deletions
|
|
@ -268,8 +268,8 @@ pub struct Mind {
|
|||
pub agent: Arc<Agent>,
|
||||
pub shared: Arc<SharedMindState>,
|
||||
pub config: SessionConfig,
|
||||
pub subconscious: Arc<tokio::sync::Mutex<Subconscious>>,
|
||||
pub unconscious: Arc<tokio::sync::Mutex<Unconscious>>,
|
||||
pub subconscious: Arc<crate::Mutex<Subconscious>>,
|
||||
pub unconscious: Arc<crate::Mutex<Unconscious>>,
|
||||
turn_tx: mpsc::Sender<(Result<TurnResult>, StreamTarget)>,
|
||||
turn_watch: tokio::sync::watch::Sender<bool>,
|
||||
/// Signals conscious activity to the unconscious loop.
|
||||
|
|
@ -309,10 +309,10 @@ impl Mind {
|
|||
sup.load_config();
|
||||
sup.ensure_running();
|
||||
|
||||
let subconscious = Arc::new(tokio::sync::Mutex::new(Subconscious::new()));
|
||||
let subconscious = Arc::new(crate::Mutex::new(Subconscious::new()));
|
||||
subconscious.lock().await.init_output_tool(subconscious.clone());
|
||||
|
||||
let unconscious = Arc::new(tokio::sync::Mutex::new(Unconscious::new()));
|
||||
let unconscious = Arc::new(crate::Mutex::new(Unconscious::new()));
|
||||
|
||||
// Spawn the unconscious loop on its own task
|
||||
if !config.no_agents {
|
||||
|
|
@ -584,6 +584,28 @@ impl Mind {
|
|||
mut input_rx: tokio::sync::mpsc::UnboundedReceiver<MindCommand>,
|
||||
mut turn_rx: mpsc::Receiver<(Result<TurnResult>, StreamTarget)>,
|
||||
) {
|
||||
// Spawn lock stats logger
|
||||
tokio::spawn(async {
|
||||
let path = dirs::home_dir().unwrap_or_default()
|
||||
.join(".consciousness/lock-stats.json");
|
||||
let mut interval = tokio::time::interval(std::time::Duration::from_secs(1));
|
||||
loop {
|
||||
interval.tick().await;
|
||||
let stats = crate::locks::lock_stats();
|
||||
if stats.is_empty() { continue; }
|
||||
let json: Vec<serde_json::Value> = stats.iter()
|
||||
.map(|(loc, s)| serde_json::json!({
|
||||
"location": loc,
|
||||
"count": s.count,
|
||||
"total_ms": s.total_ns as f64 / 1_000_000.0,
|
||||
"avg_ms": s.avg_ns as f64 / 1_000_000.0,
|
||||
"max_ms": s.max_ns as f64 / 1_000_000.0,
|
||||
}))
|
||||
.collect();
|
||||
let _ = std::fs::write(&path, serde_json::to_string_pretty(&json).unwrap_or_default());
|
||||
}
|
||||
});
|
||||
|
||||
let mut bg_rx = self.bg_rx.lock().unwrap().take()
|
||||
.expect("Mind::run() called twice");
|
||||
let mut sub_handle: Option<tokio::task::JoinHandle<()>> = None;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue