Skip to content

fix(hrr): start a fresh archive instead of resuming an earlier one - #13339

Merged
andraghetti merged 2 commits into
developfrom
users/andraghetti/hrr-capture-no-resume
Oct 14, 2026
Merged

andraghetti merged 2 commits into
developfrom
users/andraghetti/hrr-capture-no-resume

Conversation

@andraghetti

@andraghetti andraghetti commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

The capture writer resumes an archive it finds at pid-<pid>/. Since per-process archives landed, that only happens when a new process reuses an earlier process's pid with the same HIP_HRR_CAPTURE_OUTPUT, which is common in containers. The new process then adds its records to the earlier process's archive. The HRR team decided to remove resume: per-process archives made it unnecessary.

Technical Details

  • writer::open() no longer resumes. Removed: scan_events_for_resume and ScanResult, try_load_writer_state and save_writer_state_locked, index_existing_blobs_locked, resumed_file_is_ours, open_events_file, hrr_ftruncate_fd, hrr_seek_end, HRR_OPEN_APPEND, trailer stripping and torn-tail trimming on open, and the carried-over sequence, event and blob counts.
  • writer_state.json is gone. Checkpoints only flush and fsync events.bin.
  • When pid-<pid>/ holds an earlier archive (an events.bin that is a regular file with one link, owned by the capturing user), open() renames the directory to the first free pid-<pid>.prev-<n>/. It does this after the usual private-directory check. rename(2) moves the entry itself and never follows a link. One line on stderr says where the archive went. The process then records a fresh archive.
  • If the rename fails, capture is disabled with the usual Capture disabled line. The earlier archive stays where it was, unchanged.
  • Anything else at pid-<pid>/events.bin (a symbolic link, a hard link, another user's file) is not moved. The open refuses it, as before.
  • The root manifest, the reader's root resolution, hrr-playback --info and --repair on a root, and inspect_archive.py take only pid-<decimal pid> directories as process archives. Before this change they matched any pid- prefix, so a .prev-<n> directory would have been listed twice under the same pid, and a root would have read as two processes. A moved archive can still be read by pointing hrr-playback at it.
  • The reader's own torn-tail recovery and --repair are unchanged. They handle crashed archives, not resume.
  • A process that execs after HIP started now leaves its pre-exec records in pid-<pid>.prev-<n>/, instead of having them continued by the new image.
  • DESIGN.md, the producers README, the PyTorch producer comments and the enable-recording skill no longer describe resume or writer_state.json.

Issue Tracking

JIRA ID: AIRUNTIME-2915

Test Plan

  • Removed Unit_HRR_CaptureResumeTrustsOnlyItsOwnFiles, Unit_HRR_CaptureResumeCountsOnlyWholeRecords, the hidden Unit_HRR_CaptureTrimFails_Direct workload, and the two resume sections of Unit_HRR_CaptureActiveMarker. integration.yaml lists the new case set.
  • Added Unit_HRR_CaptureMovesEarlierArchiveAside. It captures a workload, copies that archive into the next run's pid-<pid>/ before the run starts, and runs it again. The earlier archive must end up byte for byte in pid-<pid>.prev-1/. The new archive must start at sequence 0 and load complete. The root manifest must list one process, and the reader must resolve the root to the new archive. A second section makes the base directory read-only: capture must be disabled and pid-<pid>/ must keep the earlier archive unchanged.
  • Negative control: the same test run against develop's hip_capture_writer.cpp must fail.
  • Added test_an_archive_moved_aside_is_not_a_process_of_the_capture to test_inspect_archive.py. It fails with develop's inspect_archive.py.
  • Unit and integration ctest on MI350X (gfx950), against a develop baseline on the same commit.

Test Result

MI350X (gfx950), GPUs 0 and 1. Each build is tested on its own and compared case by case with a develop baseline built from the same commit. The integration binary links in every run.

Run Unit ctest Integration ctest Unit cases Integration cases
develop baseline (c1faf50) pass pass 30 pass 247: 213 pass, 3 pass with warning, 7 skip, 24 non-passing
this branch pass pass 30 pass 245: 211 pass, 3 pass with warning, 8 skip, 23 non-passing
negative control (develop writer, this branch's test) pass fail 30 pass Unit_HRR_CaptureMovesEarlierArchiveAside fails
  • The non-passing integration cases are the same on develop and on this branch, apart from the removed Unit_HRR_CaptureTrimFails_Direct, a hidden workload that fails when it runs alone on develop too. The two removed resume tests passed on develop.
  • Unit_HRR_CaptureMovesEarlierArchiveAside counts as a skip in the gate because the gate runs as root: "moved aside" passes (40 assertions), and "cannot be moved" skips because root can rename in a read-only directory. Run as a non-root user, both sections pass (34 assertions).
  • Negative control: with develop's writer, the case fails as root and as non-root. Nothing is moved to pid-<pid>.prev-1, capture is not disabled when the archive cannot be moved, and the earlier archive is changed.
  • test_inspect_archive.py: 98 passed, 1 skipped. The new test fails with develop's inspect_archive.py.
  • test_hrr_capture.py: 29 passed, 27 skipped. PyTorch producer tests: 17 passed, 1 skipped.

Submission Checklist

A process whose pid-<pid> already held an archive resumed it: it scanned
events.bin or trusted writer_state.json, cut off the trailer or a torn
tail, indexed the blobs there and carried the counters on. Per-process
archives made that path dead for its original purpose, and in practice it
only ran when a new process reused an earlier one's pid with the same
HIP_HRR_CAPTURE_OUTPUT, which then added its records to that archive.

Remove resume and writer_state.json. When writer::open() finds an archive
at pid-<pid>, it renames the directory to the first free
pid-<pid>.prev-<n>, says so on stderr and starts a fresh archive. If the
rename fails, capture is disabled for the process and the earlier archive
stays as it was. The root manifest, the reader, hrr-playback and
inspect_archive.py take only pid-<decimal pid> directories for process
archives, so a moved archive is not part of the capture.

Tests: Unit_HRR_CaptureResumeTrustsOnlyItsOwnFiles,
Unit_HRR_CaptureResumeCountsOnlyWholeRecords, the hidden
Unit_HRR_CaptureTrimFails_Direct workload and the two resume sections of
Unit_HRR_CaptureActiveMarker are removed. Unit_HRR_CaptureMovesEarlierArchiveAside
is added. The registered case set changes, and integration.yaml with it.
Copilot AI balanced review requested due to automatic review settings October 13, 2026 11:42
@andraghetti
andraghetti requested review from a team as code owners October 13, 2026 11:42
@therock-pr-bot

therock-pr-bot Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

Copy link
Copy Markdown

🚫 Please fix the failed policies before requesting reviews.

The following policy checks failed:

  • ❌ PR Description

The Not ready to Review label has been added to this PR.
Once all policies pass, the label will be removed automatically.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Archive relocation can clobber a raced destination, and tooling has inconsistent PID-directory handling and messaging.

3 open findings
What changed in this PR

Removes HRR archive resumption, preserving same-PID archives under .prev-<n> while starting fresh captures.

Changes:

  • Replaces resume/checkpoint-state logic with archive relocation.
  • Excludes moved archives from root discovery and playback.
  • Updates tests and documentation for the new behavior.
File Description
projects/​clr/​hipamd/​src/​hrr/​hip_capture_writer.cpp Starts fresh archives and relocates earlier ones.
projects/​hrr/​playback/​hrr_reader.h Exposes strict PID-directory parsing.
projects/​hrr/​playback/​hrr_reader.cpp Excludes moved archives during resolution.
projects/​hrr/​playback/​hrr_playback.cpp Applies strict discovery to info and repair.
projects/​hrr/​tests/​include/​hrr_test_common.hh Updates archive test discovery.
projects/​hrr/​tests/​integration/​hrr_capture_access_test.cc Replaces resume tests with relocation coverage.
projects/​hrr/​tests/​config/​integration.yaml Updates registered integration cases.
projects/​hrr/​skills/​enable-recording/​scripts/​inspect_archive.py Excludes .prev-<n> directories.
projects/​hrr/​skills/​enable-recording/​tests/​test_inspect_archive.py Tests moved-archive exclusion.
projects/​hrr/​skills/​enable-recording/​scripts/​hrr_capture.sh Revises existing-output guidance.
projects/​hrr/​skills/​enable-recording/​tests/​test_hrr_capture.py Updates capture-merging terminology.
projects/​hrr/​skills/​enable-recording/​SKILL.md Removes writer-state documentation.
projects/​hrr/​producers/​README.md Removes resume references.
projects/​hrr/​producers/​pytorch/​hrr_torch_regions.py Updates producer behavior documentation.
projects/​hrr/​producers/​pytorch/​tests/​test_hrr_torch_regions.py Updates test commentary.
projects/​hrr/​DESIGN.md Documents fresh archives and moved-aside directories.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…rchive aside

The run command's comment, its --force note and its refusal still said that
a second run into the same --output simply reads as one merged capture. A
process of that run that reuses an earlier pid now moves that pid-<pid> to
pid-<pid>.prev-<n>, which readers of the archive root leave out. Say so there
and in the skill.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The Windows writer can follow a planted events.bin link and truncate a file outside the archive.

1 open finding
3 resolved since last review

🧠 Review effort: Balanced

@mangupta mangupta left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI-assisted pre-review (for @mangupta)

@danielbolsson danielbolsson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Read the diff and the surrounding code (the open() double-call guard, the reader and inspector pid-directory filters); the Python suites pass and the new inspect_archive test fails with its filter removed. I did not build or run the C++/GPU tests.

Non-blocking: hip_capture_writer.cpp:1083 - on Windows _O_TRUNC follows a link at events.bin (the removed branch did too); refuse a non-regular events.bin in a follow-up.

@andraghetti
andraghetti merged commit 2a8fffb into develop Oct 14, 2026
369 of 381 checks passed
@andraghetti
andraghetti deleted the users/andraghetti/hrr-capture-no-resume branch October 14, 2026 11:42
@systems-assistant

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

andraghetti added a commit that referenced this pull request Oct 16, 2026
* fix(hrr): remove the capture writer's resume leftovers
  
  writer::checkpoint() has no caller since capture resume was removed in
  #13339; the periodic flush and fsync live in append_event_locked().
  Remove it and its declaration.
  
  open() runs once at init, or in a forked child after atfork_child() has
  cleared the incomplete flag, so its own clear was only needed for a
  second archive in the same process. Drop it: a record a child dropped
  before its first open() now keeps the child's archive marked incomplete.
  
  Rewrite the comments that still described a second open() in the same
  process and a blob check against the disk; the blob check is in memory
  and covers this archive only.

* test(hrr): a forked child that marks its archive incomplete stays incomplete
  
  Unit_HRR_ForkedChildStaysIncomplete runs a workload that forks while a
  stream capture is live. The child makes the overflowing hipMemcpy3DAsync
  of Unit_HRR_OverflowingMemcpy3D_Direct, which capture drops and marks
  incomplete, before its first record opens its archive. The child's
  manifest must say "complete": false and the parent's true.
  
  Adds Unit_HRR_ForkedChildStaysIncomplete and its _Direct workload to
  tests/config/integration.yaml.

* test(hrr): require exactly one child archive in the fork incomplete test
  
  Unit_HRR_ForkedChildStaysIncomplete passed when neither manifest named the
  other process as its parent. Count the child archives, require exactly one,
  and check that the parent's manifest says "complete": true.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants