From d701d75dad33842be85e445914485ecd8d2327d1 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Mon, 28 Sep 2026 16:13:36 +0200 Subject: [PATCH 1/2] feat: enable rss tracking and memory flamegraphs by default Physical memory tracking and allocation stack capture in memory mode are no longer experimental and are enabled by default. Opt out with the new --disable-memory-track-physical / --disable-memory-capture-stack flags (env: CODSPEED_DISABLE_MEMORY_TRACK_PHYSICAL, CODSPEED_DISABLE_MEMORY_CAPTURE_STACK). The --experimental-memory-track-physical and --experimental-memory-capture-stack flags still work but are hidden and warn that they are deprecated; disable flags take precedence when both are set. --- src/cli/exec/mod.rs | 4 +-- src/cli/experimental.rs | 59 +++++++++++++++++++---------------------- src/cli/run/mod.rs | 6 +++-- src/cli/shared.rs | 8 ++++++ src/executor/config.rs | 4 +-- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/cli/exec/mod.rs b/src/cli/exec/mod.rs index 253078d91..f826ab91e 100644 --- a/src/cli/exec/mod.rs +++ b/src/cli/exec/mod.rs @@ -95,12 +95,12 @@ fn build_orchestrator_config( cycle_estimation, exclude_allocations, simulation_track_subprocess: args.shared.simulation_track_subprocess, - memory_track_physical: args.shared.experimental.experimental_memory_track_physical, + memory_track_physical: !args.shared.disable_memory_track_physical, disable_pythonmalloc_override: args .shared .experimental .experimental_disable_pythonmalloc_override, - memory_capture_stack: args.shared.experimental.experimental_memory_capture_stack, + memory_capture_stack: !args.shared.disable_memory_capture_stack, }) } diff --git a/src/cli/experimental.rs b/src/cli/experimental.rs index b4e90ebb6..42d4b22c8 100644 --- a/src/cli/experimental.rs +++ b/src/cli/experimental.rs @@ -17,24 +17,6 @@ pub struct ExperimentalArgs { )] pub experimental_fair_sched: bool, - /// Enable physical (resident) memory tracking in memory mode. - #[arg( - long, - default_value_t = false, - help_heading = "Experimental", - env = "CODSPEED_MEMTRACK_TRACK_PHYSICAL", - value_parser = clap::builder::FalseyValueParser::new() - )] - pub experimental_memory_track_physical: bool, - /// Capture allocation call stacks in memory mode. - #[arg( - long, - default_value_t = false, - help_heading = "Experimental", - env = "CODSPEED_EXPERIMENTAL_MEMORY_CAPTURE_STACK" - )] - pub experimental_memory_capture_stack: bool, - /// Do not set PYTHONMALLOC for simulation runs. #[arg( long, @@ -51,6 +33,19 @@ pub struct ExperimentalArgs { /// Deprecated alias for `--exclude-allocations`, still honored for now. #[arg(long, hide = true, env = "CODSPEED_EXPERIMENTAL_EXCLUDE_ALLOCATIONS")] pub experimental_exclude_allocations: bool, + + /// Deprecated: physical memory tracking is enabled by default. + #[arg( + long, + hide = true, + env = "CODSPEED_MEMTRACK_TRACK_PHYSICAL", + value_parser = clap::builder::FalseyValueParser::new() + )] + pub experimental_memory_track_physical: bool, + + /// Deprecated: allocation call stack capture is enabled by default. + #[arg(long, hide = true, env = "CODSPEED_EXPERIMENTAL_MEMORY_CAPTURE_STACK")] + pub experimental_memory_capture_stack: bool, } impl ExperimentalArgs { @@ -60,15 +55,9 @@ impl ExperimentalArgs { if self.experimental_fair_sched { flags.push("--experimental-fair-sched"); } - if self.experimental_memory_track_physical { - flags.push("--experimental-memory-track-physical"); - } if self.experimental_disable_pythonmalloc_override { flags.push("--experimental-disable-pythonmalloc-override"); } - if self.experimental_memory_capture_stack { - flags.push("--experimental-memory-capture-stack"); - } flags } @@ -96,25 +85,33 @@ impl ExperimentalArgs { } /// Warns about deprecated flags that graduated to stable options. They are still - /// honored, but will be removed in a future release. + /// accepted, but will be removed in a future release. pub fn warn_if_deprecated(&self) { let deprecated = [ ( self.experimental_cycle_estimation, "--experimental-cycle-estimation", - "--cycle-estimation", + "use --cycle-estimation instead", ), ( self.experimental_exclude_allocations, "--experimental-exclude-allocations", - "--exclude-allocations", + "use --exclude-allocations instead", + ), + ( + self.experimental_memory_track_physical, + "--experimental-memory-track-physical", + "physical memory tracking is enabled by default, use --disable-memory-track-physical to opt out", + ), + ( + self.experimental_memory_capture_stack, + "--experimental-memory-capture-stack", + "stack capture is enabled by default, use --disable-memory-capture-stack to opt out", ), ]; - for (_, flag, new_flag) in deprecated.iter().filter(|(set, ..)| *set) { - eprintln!( - "{flag} is deprecated and will be removed in a future release: use {new_flag} instead." - ); + for (_, flag, hint) in deprecated.iter().filter(|(set, ..)| *set) { + eprintln!("{flag} is deprecated and will be removed in a future release: {hint}."); } } } diff --git a/src/cli/run/mod.rs b/src/cli/run/mod.rs index 283499070..d5c2eb2ca 100644 --- a/src/cli/run/mod.rs +++ b/src/cli/run/mod.rs @@ -72,6 +72,8 @@ impl RunArgs { cycle_estimation: true, exclude_allocations: false, simulation_track_subprocess: false, + disable_memory_track_physical: false, + disable_memory_capture_stack: false, profiler_run_args: ProfilerRunArgs { enable_profiler: false, enable_perf: None, @@ -140,12 +142,12 @@ fn build_orchestrator_config( cycle_estimation, exclude_allocations, simulation_track_subprocess: args.shared.simulation_track_subprocess, - memory_track_physical: args.shared.experimental.experimental_memory_track_physical, + memory_track_physical: !args.shared.disable_memory_track_physical, disable_pythonmalloc_override: args .shared .experimental .experimental_disable_pythonmalloc_override, - memory_capture_stack: args.shared.experimental.experimental_memory_capture_stack, + memory_capture_stack: !args.shared.disable_memory_capture_stack, }) } diff --git a/src/cli/shared.rs b/src/cli/shared.rs index 7aba09db5..f1f22d880 100644 --- a/src/cli/shared.rs +++ b/src/cli/shared.rs @@ -139,6 +139,14 @@ pub struct ExecAndRunSharedArgs { #[arg(long, env = "CODSPEED_SIMULATION_TRACK_SUBPROCESS")] pub simulation_track_subprocess: bool, + /// Disable physical (resident) memory tracking in memory mode. + #[arg(long, env = "CODSPEED_DISABLE_MEMORY_TRACK_PHYSICAL")] + pub disable_memory_track_physical: bool, + + /// Disable allocation call stack capture in memory mode. + #[arg(long, env = "CODSPEED_DISABLE_MEMORY_CAPTURE_STACK")] + pub disable_memory_capture_stack: bool, + #[command(flatten)] pub profiler_run_args: ProfilerRunArgs, diff --git a/src/executor/config.rs b/src/executor/config.rs index 45a61f0b9..f3ec640c8 100644 --- a/src/executor/config.rs +++ b/src/executor/config.rs @@ -268,9 +268,9 @@ impl OrchestratorConfig { cycle_estimation: true, exclude_allocations: false, simulation_track_subprocess: false, - memory_track_physical: false, + memory_track_physical: true, disable_pythonmalloc_override: false, - memory_capture_stack: false, + memory_capture_stack: true, } } } From a15fad139e96d758480d97ec0e945f3590e8048d Mon Sep 17 00:00:00 2001 From: not-matthias Date: Mon, 28 Sep 2026 16:23:11 +0200 Subject: [PATCH 2/2] fix: honor falsey values of the deprecated memory flags The deprecated --experimental-memory-track-physical and --experimental-memory-capture-stack flags were parsed as plain bools and then ignored, so the old opt-out via a falsey env value (CODSPEED_MEMTRACK_TRACK_PHYSICAL=0) silently enabled tracking instead. Both flags are now Option so unset, enabled, and explicitly disabled are distinguishable. resolve_memory_track_physical() and resolve_memory_capture_stack() combine them with the new --disable-memory-track-physical / --disable-memory-capture-stack flags: any explicit opt-out wins. --- src/cli/exec/mod.rs | 6 ++++-- src/cli/experimental.rs | 25 ++++++++++++++++++------- src/cli/run/mod.rs | 10 ++++++---- src/cli/shared.rs | 15 +++++++++++++++ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/cli/exec/mod.rs b/src/cli/exec/mod.rs index f826ab91e..2302f4839 100644 --- a/src/cli/exec/mod.rs +++ b/src/cli/exec/mod.rs @@ -60,6 +60,8 @@ fn build_orchestrator_config( let modes = args.shared.resolve_modes()?; let cycle_estimation = args.shared.resolve_cycle_estimation(); let exclude_allocations = args.shared.resolve_exclude_allocations(); + let memory_track_physical = args.shared.resolve_memory_track_physical(); + let memory_capture_stack = args.shared.resolve_memory_capture_stack(); let raw_upload_url = args .shared .upload_url @@ -95,12 +97,12 @@ fn build_orchestrator_config( cycle_estimation, exclude_allocations, simulation_track_subprocess: args.shared.simulation_track_subprocess, - memory_track_physical: !args.shared.disable_memory_track_physical, + memory_track_physical, disable_pythonmalloc_override: args .shared .experimental .experimental_disable_pythonmalloc_override, - memory_capture_stack: !args.shared.disable_memory_capture_stack, + memory_capture_stack, }) } diff --git a/src/cli/experimental.rs b/src/cli/experimental.rs index 42d4b22c8..ec3155682 100644 --- a/src/cli/experimental.rs +++ b/src/cli/experimental.rs @@ -35,17 +35,28 @@ pub struct ExperimentalArgs { pub experimental_exclude_allocations: bool, /// Deprecated: physical memory tracking is enabled by default. + /// Passing a falsey value (`0`, `false`) disables it. #[arg( long, hide = true, env = "CODSPEED_MEMTRACK_TRACK_PHYSICAL", + num_args = 0..=1, + require_equals = true, + default_missing_value = "true", value_parser = clap::builder::FalseyValueParser::new() )] - pub experimental_memory_track_physical: bool, + pub experimental_memory_track_physical: Option, /// Deprecated: allocation call stack capture is enabled by default. - #[arg(long, hide = true, env = "CODSPEED_EXPERIMENTAL_MEMORY_CAPTURE_STACK")] - pub experimental_memory_capture_stack: bool, + #[arg( + long, + hide = true, + env = "CODSPEED_EXPERIMENTAL_MEMORY_CAPTURE_STACK", + num_args = 0..=1, + require_equals = true, + default_missing_value = "true" + )] + pub experimental_memory_capture_stack: Option, } impl ExperimentalArgs { @@ -99,14 +110,14 @@ impl ExperimentalArgs { "use --exclude-allocations instead", ), ( - self.experimental_memory_track_physical, + self.experimental_memory_track_physical.is_some(), "--experimental-memory-track-physical", - "physical memory tracking is enabled by default, use --disable-memory-track-physical to opt out", + "physical memory tracking is now controlled by --disable-memory-track-physical", ), ( - self.experimental_memory_capture_stack, + self.experimental_memory_capture_stack.is_some(), "--experimental-memory-capture-stack", - "stack capture is enabled by default, use --disable-memory-capture-stack to opt out", + "stack capture is now controlled by --disable-memory-capture-stack", ), ]; diff --git a/src/cli/run/mod.rs b/src/cli/run/mod.rs index d5c2eb2ca..e6750c1eb 100644 --- a/src/cli/run/mod.rs +++ b/src/cli/run/mod.rs @@ -83,10 +83,10 @@ impl RunArgs { }, experimental: ExperimentalArgs { experimental_fair_sched: false, - experimental_memory_capture_stack: false, + experimental_memory_capture_stack: None, experimental_cycle_estimation: false, experimental_exclude_allocations: false, - experimental_memory_track_physical: false, + experimental_memory_track_physical: None, experimental_disable_pythonmalloc_override: false, }, }, @@ -107,6 +107,8 @@ fn build_orchestrator_config( let modes = args.shared.resolve_modes()?; let cycle_estimation = args.shared.resolve_cycle_estimation(); let exclude_allocations = args.shared.resolve_exclude_allocations(); + let memory_track_physical = args.shared.resolve_memory_track_physical(); + let memory_capture_stack = args.shared.resolve_memory_capture_stack(); let raw_upload_url = args .shared .upload_url @@ -142,12 +144,12 @@ fn build_orchestrator_config( cycle_estimation, exclude_allocations, simulation_track_subprocess: args.shared.simulation_track_subprocess, - memory_track_physical: !args.shared.disable_memory_track_physical, + memory_track_physical, disable_pythonmalloc_override: args .shared .experimental .experimental_disable_pythonmalloc_override, - memory_capture_stack: !args.shared.disable_memory_capture_stack, + memory_capture_stack, }) } diff --git a/src/cli/shared.rs b/src/cli/shared.rs index f1f22d880..6ea9acd17 100644 --- a/src/cli/shared.rs +++ b/src/cli/shared.rs @@ -188,6 +188,21 @@ impl ExecAndRunSharedArgs { pub fn resolve_exclude_allocations(&self) -> bool { self.exclude_allocations || self.experimental.experimental_exclude_allocations } + + /// Resolves physical memory tracking. Any explicit opt-out wins: the + /// `--disable-memory-track-physical` flag overrides the deprecated enable alias, + /// and the deprecated flag's falsey value (`0`, `false`) overrides the default. + pub fn resolve_memory_track_physical(&self) -> bool { + !self.disable_memory_track_physical + && self.experimental.experimental_memory_track_physical != Some(false) + } + + /// Resolves allocation call stack capture, with the same precedence rules as + /// [`Self::resolve_memory_track_physical`]. + pub fn resolve_memory_capture_stack(&self) -> bool { + !self.disable_memory_capture_stack + && self.experimental.experimental_memory_capture_stack != Some(false) + } } #[derive(Debug, Copy, Clone, PartialEq, ValueEnum, Default)]