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:
Kent Overstreet 2026-04-12 20:27:42 -04:00
parent b94e056372
commit f56fc3a7c7
9 changed files with 286 additions and 17 deletions

View file

@ -141,8 +141,8 @@ pub struct Agent {
pub app_config: crate::config::AppConfig,
pub prompt_file: String,
pub session_id: String,
pub context: tokio::sync::Mutex<ContextState>,
pub state: tokio::sync::Mutex<AgentState>,
pub context: crate::Mutex<ContextState>,
pub state: crate::Mutex<AgentState>,
}
/// Mutable agent state — behind its own mutex.
@ -218,8 +218,8 @@ impl Agent {
app_config,
prompt_file,
session_id,
context: tokio::sync::Mutex::new(context),
state: tokio::sync::Mutex::new(AgentState {
context: crate::Mutex::new(context),
state: crate::Mutex::new(AgentState {
tools: agent_tools,
mcp_tools: McpToolAccess::All,
last_prompt_tokens: 0,
@ -255,8 +255,8 @@ impl Agent {
app_config: self.app_config.clone(),
prompt_file: self.prompt_file.clone(),
session_id: self.session_id.clone(),
context: tokio::sync::Mutex::new(ctx),
state: tokio::sync::Mutex::new(AgentState {
context: crate::Mutex::new(ctx),
state: crate::Mutex::new(AgentState {
tools,
mcp_tools: McpToolAccess::None,
last_prompt_tokens: 0,

View file

@ -123,7 +123,7 @@ fn find_project_root(file_path: &str) -> Option<String> {
const IDLE_TIMEOUT_SECS: u64 = 600;
use std::sync::OnceLock;
use tokio::sync::Mutex as TokioMutex;
use crate::Mutex as TokioMutex;
struct Registry {
configs: Vec<crate::config::LspServerConfig>,

View file

@ -10,7 +10,7 @@ use serde_json::json;
use std::sync::OnceLock;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter};
use tokio::process::{Child, ChildStdin, ChildStdout, Command};
use tokio::sync::Mutex as TokioMutex;
use crate::Mutex as TokioMutex;
#[derive(Debug, Clone)]
pub struct McpTool {

View file

@ -20,7 +20,7 @@ fn get_f64(args: &serde_json::Value, name: &str) -> Result<f64> {
args.get(name).and_then(|v| v.as_f64()).context(format!("{} is required", name))
}
async fn cached_store() -> Result<std::sync::Arc<tokio::sync::Mutex<Store>>> {
async fn cached_store() -> Result<std::sync::Arc<crate::Mutex<Store>>> {
Store::cached().await.map_err(|e| anyhow::anyhow!("{}", e))
}