Skip to content

Make profiling script failures visible instead of silently truncating#9127

Open
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:fix/profiling-silent-truncation
Open

Make profiling script failures visible instead of silently truncating#9127
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:fix/profiling-silent-truncation

Conversation

@tautschnig

Copy link
Copy Markdown
Collaborator

Profiling a long-running benchmark could produce a report saying only "Insufficient samples collected", indistinguishable from a genuinely short benchmark, when in fact the run had been killed by the timeout or perf post-processing had failed. Several fixes:

  • Record a timed_out flag per benchmark (propagated through multi-run averaging), warn loudly when a run is KILLED by the timeout, and list the affected benchmarks in the final report instead of the generic insufficient-samples message.
  • Warn when perf.data exists but yields zero parsed samples, distinguishing a truncated recording from a too-short benchmark.
  • Sample at 297 Hz instead of 997 Hz when the timeout indicates a long-running benchmark: DWARF stack recording at 997 Hz produces multi-GB perf.data files and enough overhead that the benchmark itself may no longer finish within the timeout.
  • Pass --no-buildid to perf record and --no-inline to perf report and perf script, and bound perf report with a timeout: build-id and inlined-frame post-processing spawn addr2line processes that were observed to hang indefinitely on stale ~/.debug build-id cache entries, stalling the whole profiling run after the benchmark had already completed. Neither is needed: results are analyzed in place, and the parsed report lines and collapsed stacks do not use inlined frames.
  • Each commit message has a non-empty body, explaining why the change was made.
  • n/a Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • n/a White-space or formatting changes outside the feature-related changed lines are in commits of their own.

Profiling a long-running benchmark could produce a report saying only
"Insufficient samples collected", indistinguishable from a genuinely
short benchmark, when in fact the run had been killed by the timeout or
perf post-processing had failed. Several fixes:

- Record a timed_out flag per benchmark (propagated through multi-run
  averaging), warn loudly when a run is KILLED by the timeout, and list
  the affected benchmarks in the final report instead of the generic
  insufficient-samples message.
- Warn when perf.data exists but yields zero parsed samples,
  distinguishing a truncated recording from a too-short benchmark.
- Sample at 297 Hz instead of 997 Hz when the timeout indicates a
  long-running benchmark: DWARF stack recording at 997 Hz produces
  multi-GB perf.data files and enough overhead that the benchmark
  itself may no longer finish within the timeout.
- Pass --no-buildid to perf record and --no-inline to perf report and
  perf script, and bound perf report with a timeout: build-id and
  inlined-frame post-processing spawn addr2line processes that were
  observed to hang indefinitely on stale ~/.debug build-id cache
  entries, stalling the whole profiling run after the benchmark had
  already completed. Neither is needed: results are analyzed in place,
  and the parsed report lines and collapsed stacks do not use inlined
  frames.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
@tautschnig tautschnig self-assigned this Jul 22, 2026
Copilot AI review requested due to automatic review settings July 22, 2026 09:10
@tautschnig
tautschnig requested review from a team, kroening and peterschrammel as code owners July 22, 2026 09:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Improves profiling robustness by making perf/timeout failures explicit (rather than appearing as “insufficient samples”), and by reducing perf overhead for long-running benchmarks.

Changes:

  • Add per-benchmark timed_out tracking and surface timeout-killed runs in the final “no samples” report.
  • Adjust perf recording/reporting to avoid known hangs (--no-buildid, --no-inline) and add timeouts around perf report.
  • Reduce sampling frequency for long-timeout benchmarks to control perf.data size/overhead.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
scripts/profiling/runner.py Adds timeout visibility, adaptive sampling frequency, and safer perf invocation/processing.
scripts/profiling/analysis.py Improves final “no samples” message by listing benchmarks killed by timeout.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +16 to +23
# Sampling frequency for perf record. For benchmarks that are expected to
# run long (large timeout), DWARF stack recording at 997 Hz produces
# multi-GB perf.data files and enough recording overhead that the benchmark
# itself may no longer finish within the timeout. 297 Hz still yields plenty
# of samples on runs of a minute or more.
SAMPLING_FREQ = 997
SAMPLING_FREQ_LONG = 297
LONG_RUN_TIMEOUT = 300
Comment on lines +150 to +154
report = subprocess.run(
["perf", "report", "-i", str(perf_data), "--stdio", "--no-inline",
"--no-children", "--percent-limit", "0.5", "-n"],
capture_output=True, text=True, timeout=300)
report_stdout = report.stdout
Comment on lines +153 to +158
capture_output=True, text=True, timeout=300)
report_stdout = report.stdout
except subprocess.TimeoutExpired:
report_stdout = ""
warn(f"[{name}] perf report timed out after 300s — no hotspot data "
f"for this benchmark")
# CI containers/VMs).
perf_event = _detect_perf_event()

freq = SAMPLING_FREQ if timeout <= LONG_RUN_TIMEOUT else SAMPLING_FREQ_LONG
Comment on lines 307 to 308
if script.returncode != 0:
warn(f"[{result['name']}] perf script failed (exit {script.returncode})")
@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.82%. Comparing base (f71fdad) to head (1072d21).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #9127      +/-   ##
===========================================
- Coverage    80.83%   80.82%   -0.01%     
===========================================
  Files         1715     1715              
  Lines       189948   189948              
  Branches        73       73              
===========================================
- Hits        153540   153533       -7     
- Misses       36408    36415       +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants