github robintra/perf-sentinel v0.5.8

latest releases: chart-v0.2.58, v0.8.12, chart-v0.2.57...
one month ago

What's new in v0.5.8

v0.5.7 introduced the sanitizer-aware reclassification heuristic with three modes (Auto, Always, Never) and an OR rule across the two signals (ORM scope marker, timing variance). On Spring Data and EF Core stacks, the ORM scope is present on practically every JDBC/ADO span, so under Auto the OR rule fires on every sanitized SQL group whose ORM marker is in the chain. That was the right default for catching N+1 patterns hidden by the agent sanitizer, but it also meant operators lost the ability to surface legitimate redundant_sql findings on truly repeated identical queries (cache-warming loops, polling repositories, unmemoized findById(sameId) in legacy code) since those would silently flip to n_plus_one_sql with the wrong remediation.

v0.5.8 adds a fourth Strict mode that requires both signals to fire conjointly (AND): the ORM scope must be present and the per-span timing variance must clear the empirical CV > 0.5 threshold. Default stays Auto, so production users on Spring Data, EF Core and similar stacks see no behavior change on upgrade. Operators who want to recover redundant_sql precision on cached identical queries opt in with [detection] sanitizer_aware_classification = "strict" in .perf-sentinel.toml.

The trade-off is explicit: Auto favors recall (catches all ORM-induced N+1), Strict favors precision (preserves redundant_sql findings on cached identical queries). Findings reclassified under Strict carry the same classification_method = "sanitizer_heuristic" JSON marker as findings reclassified under Auto or Always, so downstream JSON consumers and inspect TUI rendering behave identically. GreenOps aggregates (green_summary.avoidable_io_ops, IIS, waste ratio, top_offenders ranking) are preserved across modes because both n_plus_one_sql and redundant_sql weight identically into the avoidable-I/O bucket and the score::compute dedup key collapses any double-counting risk.

Added

  • [detection] sanitizer_aware_classification = "strict" (4th value, opt-in). Reclassifies a sanitized SQL group as n_plus_one_sql only when the ORM scope marker AND the timing variance signal fire conjointly. Recommended on environments where actionable redundant_sql findings are valuable signal that should not be silently absorbed into n_plus_one_sql. See docs/CONFIGURATION.md and docs/design/04-DETECTION.md for the full recall-vs-precision dial across the four modes.
  • SanitizerAwareMode::Strict enum variant and classify_sanitized_sql_group_strict public function in crates/sentinel-core/src/detect/sanitizer_aware.rs. The new function takes the same (spans, scopes) arguments as classify_sanitized_sql_group and returns LikelyNPlusOne only when has_orm_scope && timing_variance_suggests_n_plus_one. Short-circuits on the cheap ORM-scope check, so on non-ORM stacks Strict is strictly cheaper than Auto (the variance computation is skipped entirely).

Changed

  • BREAKING (perf-sentinel-core, pre-1.0 so minor-bump allowed): classify_sanitized_sql_group_indexed (the hot-path entry called from detect_n_plus_one) now takes a mode: SanitizerAwareMode parameter and dispatches between the OR-logic (classify_sanitized_sql_group) and the AND-logic (classify_sanitized_sql_group_strict) based on the mode. External consumers calling this directly must pass the mode explicitly.
  • Always mode now short-circuits in detect_n_plus_one::classify_group before the verdict computation. Pure cleanup, no observable behavior change: the verdict was already ignored by the emit gate under Always, so running has_orm_scope and timing_variance_suggests_n_plus_one was wasted allocation. On traces with many sanitized SQL groups under Always, this trims a Vec<&NormalizedEvent> allocation and a collect_scopes Vec<String> clone per group.
  • classify_sanitized_sql_group_indexed dispatch is now exhaustive (no _ wildcard): Strict matches one arm, Auto | Always | Never matches the other. A future fifth variant on SanitizerAwareMode will fail to compile here rather than silently fall through to the OR logic.
  • classify_sanitized_sql_group (the OR-logic public entry) is now a single boolean OR instead of two sequential if returns. Behavior unchanged.

Behavior

  • Default behavior unchanged: Auto still emits on either signal.
  • Strict does NOT change green_summary aggregates: both n_plus_one_sql and redundant_sql weight identically into avoidable_io_ops, and the score::compute dedup key is (trace_id, template, source_endpoint). Only the per-finding type label and the suggestion text differ between modes.
  • Under Strict, the timing-variance threshold becomes load-bearing: it is the only gate that lets a sanitized group reach LikelyNPlusOne once the ORM scope check has passed. Real ORM-induced N+1 against a fully warm row cache (e.g. 100 lookups by primary key with all rows in shared_buffers) can cluster within ±10% (CV ~ 0.1) and stay silent under Strict. The 0.5 threshold is preserved across modes pending empirical validation in the simulation lab. If lab traffic shows the threshold to be too restrictive under Strict, the right follow-up is exposing a [detection] sanitizer_aware_min_cv knob rather than picking a new global default.

Install

Prebuilt binaries (Linux amd64 / arm64, macOS arm64, Windows amd64):

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.8/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinel

Linux binaries are statically linked against musl and run on any distribution (Alpine, Debian, RHEL, Ubuntu any version) regardless of glibc version, and inside FROM scratch images.

From crates.io:

cargo install perf-sentinel

Docker:

docker run --rm -p 4317:4317 -p 4318:4318 \
  ghcr.io/robintra/perf-sentinel:0.5.8 watch --listen-address 0.0.0.0

Also available on Docker Hub: robintrassard/perf-sentinel:0.5.8.

Helm (chart 0.2.11 ships 0.5.8 as its appVersion default):

helm install perf-sentinel oci://ghcr.io/robintra/charts/perf-sentinel \
  --version 0.2.11 \
  --namespace observability --create-namespace

Verify the binary against SHA256SUMS.txt:

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.8/SHA256SUMS.txt
sha256sum -c SHA256SUMS.txt --ignore-missing

Full diff: v0.5.7...v0.5.8

Don't miss a new perf-sentinel release

NewReleases is sending notifications on new releases.