#![cfg(feature = "profiling-rss-probe")]
use std::process::{Command, Output};
const MAX_MIB_PER_HOUR: f64 = 25.0;
fn describe(out: &Output) -> String {
format!(
"status={:?}\n--- stdout ---\n{}\n--- stderr ---\n{}",
out.status.code(),
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr),
)
}
fn field(stdout: &str, key: &str) -> Option<f64> {
stdout
.lines()
.find(|l| l.starts_with("RSS_PROBE_OK"))?
.split_whitespace()
.find_map(|tok| tok.strip_prefix(key)?.parse().ok())
}
fn run_probe(profiling: bool) -> (Output, String) {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_rss-probe"));
if !profiling {
cmd.env("RSS_PROBE_NO_PROFILING", "1");
}
let out = cmd.output().expect("spawn rss-probe");
let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
(out, stdout)
}
fn assert_measured(out: &Output, stdout: &str) {
assert!(
stdout.contains("RSS_PROBE_OK"),
"probe did not complete a measurement.\n{}",
describe(out)
);
assert!(
out.status.success(),
"probe exited non-zero.\n{}",
describe(out)
);
let spans = field(stdout, "spans=").unwrap_or(0.0);
assert!(
spans >= 1000.0,
"probe reported implausibly little span load ({spans}).\n{}",
describe(out)
);
let samples = field(stdout, "samples=").unwrap_or(0.0);
assert!(
samples >= 20.0,
"probe collected too few RSS samples ({samples}) to fit a slope.\n{}",
describe(out)
);
}
#[test]
#[ignore = "takes ~130s (two probe runs); run via `make ci-rss-probe`"]
fn profiling_bridge_adds_no_rss_growth_under_span_load() {
let (with_out, with_stdout) = run_probe(true);
assert_measured(&with_out, &with_stdout);
let (without_out, without_stdout) = run_probe(false);
assert_measured(&without_out, &without_stdout);
let with_slope = field(&with_stdout, "mib_per_hour=")
.unwrap_or_else(|| panic!("no mib_per_hour.\n{}", describe(&with_out)));
let without_slope = field(&without_stdout, "mib_per_hour=")
.unwrap_or_else(|| panic!("no mib_per_hour.\n{}", describe(&without_out)));
let attributable = with_slope - without_slope;
println!(
"profiling bridge RSS: with={with_slope:.2} MiB/h without={without_slope:.2} MiB/h \
attributable={attributable:.2} MiB/h (ceiling {MAX_MIB_PER_HOUR:.1})"
);
assert!(
attributable < MAX_MIB_PER_HOUR,
"profiling bridge added {attributable:.2} MiB/h over the no-profiling \
control (ceiling {MAX_MIB_PER_HOUR:.1}); with={with_slope:.2} \
without={without_slope:.2}. This is the brefwiz-spiffe OOM regression \
— check whether anything reintroduced per-span pyroscope tagging.\n\
--- with profiling ---\n{}\n--- control ---\n{}",
describe(&with_out),
describe(&without_out),
);
}
#[test]
fn profiling_bridge_does_not_wire_per_span_tagging() {
let src = include_str!("../src/profiling.rs");
let calls: Vec<&str> = src
.lines()
.map(str::trim)
.filter(|l| l.contains("tag_wrapper()") && !l.starts_with("//") && !l.starts_with("///"))
.collect();
assert!(
calls.is_empty(),
"src/profiling.rs calls tag_wrapper(), which arms per-span pyroscope \
tagging: every tag call rebuilds and clears the whole profile \
(~87,000/s measured), which grew RSS 7.4 MiB/h against 1.0 without and \
OOM-killed brefwiz-spiffe every ~5.5h against a 512Mi cgroup. It also \
emptied the profiles it was meant to enrich. Offending lines: {calls:?}"
);
let layer_impl = src
.split("impl<S> tracing_subscriber::Layer<S> for ProfilingTagLayer")
.nth(1)
.expect("ProfilingTagLayer Layer impl not found — has it been renamed?");
let body = &layer_impl[..layer_impl.find("\n}").unwrap_or(layer_impl.len())];
assert!(
!body.contains("fn on_enter") && !body.contains("fn on_exit"),
"ProfilingTagLayer has regained span callbacks; it is supposed to be \
inert. Body:\n{body}"
);
}