Skip to content

refactor(rocprofiler-sdk): address review feedback on #8887 for remove-callbacks-spm - #10098

Merged
amd-vkale merged 6 commits into
users/vkale/remove-callbacks-spmfrom
users/vkale/remove-callbacks-spm-cursor-fixes
Aug 18, 2026
Merged

amd-vkale merged 6 commits into
users/vkale/remove-callbacks-spmfrom
users/vkale/remove-callbacks-spm-cursor-fixes

Conversation

@amd-vkale

@amd-vkale amd-vkale commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

This PR isolates the counter-collection slice of the callback-removal effort (reference PRs
#8730 / #8586) into a small, single-service change, per review guidance to land callback removal
one service at a time.

It is one of four sibling migrations, each independently reviewable:

Service PR Status
Thread trace #8790 approved
PC sampling #8895 approved
SPM #8887 in review
Counter collection this PR in review

Kernel replay (#7960, #8622) is greatly enhanced by this change, but the two are independent.
This PR is behavior-preserving on its own and should merge into develop cleanly with or without
the kernel replay feature.

Technical Details

Counter collection no longer registers a queue_callbacks_t with the HSA queue controller. The HSA
write interceptor and the async signal handler now call explicit free functions instead.

New — counters/queue_hooks.{hpp,cpp}

  • write_hook, signal_completion_hook, is_any_active, each iterating active
    dispatch_counter_collection contexts and calling the existing queue_cb / completed_cb.
  • The hooks are deliberately thin: this PR changes how the callbacks are reached, not what they
    do.

New — hsa/queue_hooks/client_ids.hpp

  • Stable producer tags for inst_pkt_t entries. All four service ids are reserved up front, not
    just the one this PR needs, so the tag values stay stable as each remaining service migrates and
    test ordering does not shift underneath the later PRs.

Changed

  • The WriteInterceptor gate and the should_batch predicate detect counters via
    is_any_active(); counter collection no longer contributes to queue.get_notifiers().
  • Removes the now-unused queue_id from counter_callback_info.
  • Updates the counter tests off iterate_callbacks.

Deliberately not changed

  • The per-queue callback registry stays in place for thread trace, PC sampling and SPM. It is
    removed only once all four services are migrated.
  • The callback thread (callback_thread_start / callback_thread_stop) is preserved.

Rebase, 12 Aug

Rebased onto develop at 20bb64fb32 to clear the merge conflict. There was exactly one conflict
and it was mechanical: develop renamed firmware_restrictions.cpp to
firmware_restrictions_test.cpp while this branch added queue_hooks_test.cpp, so both entries
now appear in counters/tests/CMakeLists.txt.

No source changes were made during the rebase. The diffstat is unchanged at 300 insertions, 82
deletions across 12 files
, which is the check that nothing drifted. The two stacked PRs were
restacked at the same time and both remain mergeable.

Relationship to the stacked PRs

#8891  (this PR)          migration only
  └── #9586               review feedback: completion routing, hook renames, enum, copyright
        └── #9868         per-agent scoping for counter collection

Review feedback on this PR is intentionally not applied here, to keep this PR a pure mechanical
migration that is easy to verify by inspection:

Reviewers who want to see the end state rather than the increment should read #9586 alongside this
PR.

Issue Tracking

AIPROFSDK-1017.

Motivated by the kernel replay work tracked under AIPROFSDK-68; see #7960 for why the callback
registry is a problem for replay. This PR does not depend on that work.

Test Plan

The migration is intended to be behaviour-preserving, so the real coverage is the existing suite
rather than new tests.

  • New unit test — counters/tests/queue_hooks_test.cpp,
    counters_queue_hooks.is_any_active_false_when_no_context_active. is_any_active() replaces the
    queue.get_notifiers() signal the old registry gave the write-interceptor gate; with no
    dispatch-counter-collection context active it must report inactive. Requires no GPU or HSA
    runtime, so it runs everywhere.
  • Existing counter-collection unit tests — counters/tests/core.cpp, updated off
    iterate_callbacks to the new hook surface.
  • Existing rocprofv3 counter-collection integration tests — unchanged, and the primary signal
    that the migration preserved behaviour.

Test Result

CI is re-running after the 12 Aug rebase; the results below describe the state before it, which
the rebase should not have altered since it touched only a CMake source list.

Known failures, fixed in #9586. Two pre-existing integration tests fail on this PR and pass on
develop:

rocprofv3-test-roctx-pause-resume-tracing.test_counter_collection_data
rocprofv3-test-counter-collection-pmc-selected-regions
  .test_counter_collection_only_inside_selected_regions

Both are pause/resume counter-collection tests, and pause is stop_context — which is exactly the
completion-routing regression @bwelton identified. They are an objective target for #9586 rather
than tests authored alongside the fix.

Not caused by this PR, for whoever triages the check list:

  • Analyze (actions) and Analyze (python) fail with a workflow template error rather than a
    finding — .github/workflows/rocprofiler-sdk-codeql.yml, "Unexpected value ''". The jobs never
    run, and this affects every PR in the repository.
  • therock-pr-bot reports Timed out waiting for required checks to complete and is downstream of
    the above.
  • 6.2 • ubuntu-22.04 • aqlprofile-internal failed in image setup with a GPGKeyTemporarilyNotFoundError
    and an HTTP 500 from the package host.

For calibration: #8790 and #8895 are approved with zero real failures, and their check lists
contain exactly those same three repo-wide jobs.

Submission Checklist

cursoragent and others added 4 commits July 30, 2026 04:43
Address review feedback on #8887 with the same completion-routing and
stop_context lifecycle fixes applied for counters in #8891.

signal_completion_hook iterates registered SPM contexts; stop_context
stops queue-interposed services before deactivating the context slot.
Adds queue_hooks regression test for stop-then-complete ordering.

Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Per review feedback from @SrirackshaNag: the queue_controller_sync() in
spm::stop_context was there to handle in-flight dispatches and to avoid dangling
callback pointers once the per-queue callbacks were unregistered. Neither reason
survives the hook migration.

- dangling pointers: nothing is registered any more; signal_completion_hook is a
  static function that resolves contexts at completion time.
- in-flight dispatches: handled by signal_completion_hook routing over registered
  rather than active contexts (previous commit on this branch). post_kernel_call
  never gated on the enabled flag, so the completion runs normally.

Two further reasons a drain might have been needed, both checked and neither
applicable:

- serializer transition: profiler_serializer::disable() records the previous
  state and pushes an hsa_barrier across the queues, and kernel_completion_signal
  reconciles in-flight dispatches against it. The transition is GPU-ordered and
  does not require the CPU to observe an idle GPU.
- service teardown: spm::stop_context frees no buffer, destroys no profile and
  stops no hardware, so nothing it touches has a lifetime that ends here.

Note the drain was never a guarantee in any case: Queue::sync uses a 5 s hint and
only warns on timeout, and _active_kernels counts intercepted dispatches only.

Also re-justifies the context::stop_context ordering. It is kept, but not for the
reason originally given: with no drain, the point is that disable_serialization()
runs before dispatches stop being instrumented, so no dispatch is submitted
without serializer packets while the serializer is still enabled.

Comments in spm_core.stop_context_sync_and_restart updated to match; the test
name is left alone to avoid churn in existing local test invocations.

Open question for @SrirackshaNag: the drain also incidentally covered
stop_context followed by destroying the counter config. If any tool does that,
the guard belongs at spm_destroy_profile rather than at stop.

Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…s not address

Comment-only. Names the two blocking issues raised in the review of #8887 and how
each is handled, so a reader does not have to reconstruct it from the review.

spm/queue_hooks.cpp: states the consequence of dropping an in-flight completion --
the DISPATCH_END record, kfd_stop() and barrier-signal cleanup are all skipped and
the map entry leaks -- and records why widening to registered contexts stays
per-origin: each context's post_kernel_call only claims packets in its own
packet_return_map. That matters because, unlike dispatch_counter_collection, there
is no conflict guard rejecting a second concurrent dispatch_spm context.

spm/core.cpp: marks the drain removal as a deliberate divergence from the review,
which asked for the sync to be kept plus an explicit draining state. The
serialization window that state would protect is closed instead by
context::stop_context running this function before clearing the active slot, so
disable_serialization happens while the enter hook can still see the context. The
two approaches are not obviously equivalent, so the reasoning is recorded rather
than left implicit, and it should be revisited if that ordering changes.

Co-authored-by: Vivek Kale <vivek.kale@amd.com>
… priority

Restores the queue_controller_sync() an earlier commit on this branch removed. The
review of #8887 asked for it to be kept, with SPM held visible to the enter hook and
to serialization through a draining window until it and disable_serialization()
complete. That takes precedence over the later suggestion to remove it.

The removal argued that the sync's two original purposes were addressed by the
migration: dangling callback pointers, and letting in-flight dispatches complete.
The first is genuinely gone -- nothing is registered any more. The second does not
survive scrutiny: provenance routing guarantees that a completion which arrives is
delivered, whereas the drain bounds when completions arrive at all, and the rest of
the teardown depends on the latter. The comment now records both the request and why
the counter-argument is weaker than it appeared, so this is not relitigated silently.

No draining flag is introduced, because the visibility half already comes from
ordering: context::stop_context calls this function while the context is still in
the active list, so throughout the drain the enter hook still reaches
pre_kernel_call, whose disabled path deliberately returns serialize=true to
coordinate the serialized->unserialized transition, and the slot is cleared only
after this function returns. The comment marks that ordering as load-bearing -- if
the slot were cleared first, the enter hook would go blind before
disable_serialization() ran and a dispatch could be submitted unserialized while the
serializer was still enabled.

Also brings this branch's own earlier additions into clang-format compliance; they
had not been formatted. Verified with clang-format 11.1.0, the version the repo
pins, and confined to lines this branch adds -- nothing pre-existing is reformatted.

Not compiled here -- no ROCm toolchain in this environment.

Co-authored-by: Vivek Kale <vivek.kale@amd.com>
@amd-vkale
amd-vkale requested a lite review from Copilot August 14, 2026 20:06
@amd-vkale
amd-vkale marked this pull request as ready for review August 14, 2026 20:06
@amd-vkale
amd-vkale requested review from a team as code owners August 14, 2026 20:06

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.

Pull request overview

This PR updates the rocprofiler-sdk SPM queue hook routing and context shutdown ordering to preserve in-flight dispatch completion behavior after callback-registry removal, and adds a regression test to validate the new hook path.

Changes:

  • Route SPM completion handling via registered (not only active) contexts to ensure in-flight dispatches still complete after stop_context.
  • Adjust context::stop_context ordering so queue-interposed services stop before clearing the active slot, preserving serialization/enter-hook visibility guarantees.
  • Add a regression unit test covering the stop-before-completion scenario and update related test comments.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/core.cpp Adds a regression test exercising the queue_hooks completion path after stop_context; updates stop-context test comments.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/queue_hooks.hpp Documents completion hook behavior to iterate registered contexts for provenance-based routing.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/queue_hooks.cpp Implements completion routing over registered contexts; keeps enter hook / is_any_active() based on active contexts.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/core.cpp Restores/clarifies drain-before-disable-serialization rationale and ordering requirements in spm::stop_context.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/context/context.cpp Stops queue-interposed services before clearing the active slot to avoid instrumentation/serialization ordering gaps.
Suppressed comments (1)

projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/core.cpp:1075

  • This continue path also skips rocprofiler_spm_destroy_counter_config(expected.id) even though the counter config was already created earlier in the loop iteration, leaking the config.
            size_t map_size_before_stop = 0;
            cb_info->packet_return_map.rlock(
                [&](const auto& data) { map_size_before_stop = data.size(); });
            if(map_size_before_stop == 0) continue;

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

@amd-vkale

Copy link
Copy Markdown
Contributor Author

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested change, apply the suggestion exactly.

Do not make changes beyond what is described in the linked review thread.

… leak

Co-authored-by: amd-vkale <291155109+amd-vkale@users.noreply.github.com>

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested change, apply ...

Fixed in commit fix(spm/tests): destroy counter config before early continue to avoid leak. Both early-continue paths now call rocprofiler_spm_destroy_counter_config(expected.id) before skipping to the next iteration.

@cursor

cursor Bot commented Aug 18, 2026

Copy link
Copy Markdown

Automated stacked-PR status check (Cursor)

Stack position: develop → #8887 → #10098 → #9932. Not yet eligible for the automatic rebase+merge.

Why:

Remaining steps:

  1. Resolve refactor(rocprofiler-sdk): migrate SPM off the per-queue callback registry #8887's two blocking issues (dropped in-flight completions, serialization gap) and get it approved.
  2. Investigate and fix the Core/build/coverage CI failures (6 distinct failing jobs — looks like a real break, not flake).
  3. Run clang-format on spm/tests/core.cpp.
  4. Request a review.
  5. Rebase onto current develop once refactor(rocprofiler-sdk): migrate SPM off the per-queue callback registry #8887 is close to landing — expect real conflicts given the drift.

Posted by an automated stacked-PR status check — no code or branch changes were made.

@amd-vkale

Copy link
Copy Markdown
Contributor Author

Mergeability (local review + GPU unit tests, 2026-08-18)

Ready to fast-forward into #8887 after one test-only compile fix. #8887's tip is an ancestor of this head.

The production change matches the #8891/#9586 liveness fix that @bwelton requested here as well: signal_completion_hook iterates registered SPM contexts, and stop_context runs the SPM stop/drain before clearing the active slot.

Local results:

  • Library + spm-counter-test compile after replacing context::correlation_id corr_id{.internal = 99} with default-construction + assignment (same non-aggregate issue refactor(rocprofiler-sdk): address review feedback on #8891 for remove-callbacks-counters #9586 already fixed for counters). Without that, this PR does not build; that is consistent with the current Core CI red.
  • spm_queue_hooks.is_any_active_false_when_no_context_active — pass in isolation
  • spm_core.stop_context_removes_callbacks — pass
  • spm_queue_hooks.stop_context_in_flight_completion_routes_via_hook_path — compiles after the constructor fix, then skips (is_spm_supported_arch does not accept this GPU). So the hook-path assertion was not GPU-exercised here; the routing code is the same pattern that did pass on counters.

Not folding #9932 on top (see comment there): no human review, and it has diverged from this head by the later test-leak commit.

I will include the two-line correlation_id constructor fix when this is fast-forwarded into #8887.

… its default ctor

The designated initializer does not compile: correlation_id is not an aggregate.
Same pattern #9586 already used for the counters hook-path test, without which

Co-authored-by: Cursor <cursoragent@cursor.com>
#10098 cannot build.
@amd-vkale
amd-vkale merged commit 01d66a3 into users/vkale/remove-callbacks-spm Aug 18, 2026
1 check passed
@amd-vkale
amd-vkale deleted the users/vkale/remove-callbacks-spm-cursor-fixes branch August 18, 2026 05:59
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