rust-lang/rust-analyzer · error
profiler already started
Error message
profiler already started
What it means
The google_cpu_profiler wrapper in the `profile` crate is single-instance: an atomic STATE machine enforces OFF -> PENDING -> ON transitions. `start` panics with 'profiler already started' if the profiler is not in the OFF state when starting, i.e. a previous session was never stopped.
Source
Thrown at crates/profile/src/google_cpu_profiler.rs:29
#[allow(non_snake_case)]
unsafe extern "C" {
fn ProfilerStart(fname: *const c_char) -> i32;
fn ProfilerStop();
}
const OFF: usize = 0;
const ON: usize = 1;
const PENDING: usize = 2;
fn transition(current: usize, new: usize) -> bool {
static STATE: AtomicUsize = AtomicUsize::new(OFF);
STATE.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok()
}
pub(crate) fn start(path: &Path) {
if !transition(OFF, PENDING) {
panic!("profiler already started");
}
let path = CString::new(path.display().to_string()).unwrap();
if unsafe { ProfilerStart(path.as_ptr()) } == 0 {
panic!("profiler failed to start")
}
assert!(transition(PENDING, ON));
}
pub(crate) fn stop() {
if !transition(ON, PENDING) {
panic!("profiler is not started")
}
unsafe { ProfilerStop() };
assert!(transition(PENDING, OFF));
}
View on GitHub (pinned to e8f7e90aa3)
Solutions
- Ensure every `start()` is paired with `stop()`, including on error paths (use a guard or defer pattern)
- Check current state before starting, or restructure to start profiling once and toggle collection instead
- Fix the exception/interrupt path that skipped the previous `stop()` call
Example fix
// before profiler::start(&path); run_work(); // early return skips stop profiler::start(&path); // panics // after profiler::start(&path); let result = run_work(); profiler::stop(); result
Defensive patterns
Strategy: try-catch
Validate before calling
// no public state accessor; guard at call site
static PROFILING: AtomicBool = AtomicBool::new(false);
fn can_start() -> bool { !PROFILING.load(Ordering::SeqCst) } Try / catch
std::panic::catch_unwind(|| profiler::start(&path))
.err()
.map(|_| eprintln!("profiler already running; skipping start")); Prevention
- Pair every start() with exactly one stop(), including on early-return paths
- Use a guard type (Drop impl) that calls stop automatically
- Never start profiling twice in one process; toggle at a higher level instead
- Avoid concurrent profiling start from multiple threads
When it happens
Trigger: Calling `profile::start()` twice without an intervening `stop()`; a prior `stop()` failed or was skipped; concurrent startup from two threads (the compare_exchange ensures only one wins).
Common situations: Long-lived processes toggling CPU profiling where an early error path skipped `stop()`; tests or tools that start profiling in each iteration without cleanup; two profiling entry points racing.
Related errors
- profiler is not started
- profiler failed to start
- We explicitly do not provide canonicalization API, as that i
- bad kind {other}
- bad spacing {other}
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/4c20142988d62196.
Report an issue: GitHub.