Repository navigation
Conversation
…istry Isolates the SPM 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. Independent of kernel replay. SPM no longer registers a queue_callbacks_t with the HSA queue controller. Instead the HSA write interceptor and async signal handler call explicit free functions: - spm::write_hook / signal_completion_hook / is_any_active (new spm/queue_hooks.{hpp,cpp}) iterating active dispatch_spm contexts and calling the existing pre_kernel_call / post_kernel_call - hsa/queue_hooks/client_ids.hpp: stable inst_pkt producer tags The per-queue callback registry is intentionally retained for counters, thread-trace and pc-sampling; those migrate in follow-up PRs. The WriteInterceptor gate and should_batch predicate detect SPM via is_any_active() (it no longer contributes to queue.get_notifiers()). Removes the now-unused queue_id from spm_counter_callback_info and updates spm tests off iterate_callbacks. Co-authored-by: Cursor <cursoragent@cursor.com>
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>
… leak Co-authored-by: amd-vkale <291155109+amd-vkale@users.noreply.github.com>
Apply per-agent scoping from PR #9868 to the SPM callback-removal branch: - Per-agent serialization ref-counting in queue_controller - agents set on spm_dispatch_counter_collection_service with collects_on/intersects - rocprofiler_spm_dispatch_counting_service_set_agents() public API - Agent filtering in spm::write_hook and disjoint SPM context conflict rules Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Apply clang-format 11 to queue_controller and construct correlation_id via its constructor in the SPM stop_context completion test. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
The dispatch_thread_trace stop call fits on one line under the project clang-format profile. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…add set_agents/disjoint-context tests Co-authored-by: amd-vkale <291155109+amd-vkale@users.noreply.github.com>
- Skip SPM completion hook when inst_pkt has no SPM_CLIENT_ID tag - Cache is_any_active() once per WriteInterceptor invocation - Add unit test for exit-hook skip path Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ook test stop_context_in_flight_completion_routes_via_hook_path set corr_id.internal to 99 but never expected.correlation_id, so user_dispatch_cb compared against 0. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…id range The inst_pkt_t tag space is shared between the per-queue callback registry and the queue hooks. QueueController::add_callback allocates strictly positive ids counting up from 1, which is exactly the range the hook tags used, so a packet tagged by a not-yet-migrated service could compare equal to a hook tag. This was inert while the tags were only carried and never inspected, but counters, thread trace and SPM now each select their own packets by comparing against their tag, so the overlap is reachable. Move the tags to a negative range, which the registry cannot produce, and add a static_assert so the invariant survives future additions. Also converts the tags from separate constexpr int64_t values to an unscoped enum with a fixed int64_t underlying type, keeping the implicit conversion to hsa::ClientID so call sites need no casts. (cherry picked from commit 4e1e51a)
…ng races Two races in QueueController, both reported in review and both still open. serializer() read the per-agent refcount, released it, and only then looked up or inserted the serializer entry. A concurrent update_serialization() in that gap finds no entry to transition, so the entry is created from a stale observation and keeps the wrong state indefinitely: created from a stale `true` it stays serialized at refcount zero, created from a stale `false` the first dispatch runs unserialized. Hold the refcount read lock across the lookup and insertion so the observation and the insertion are atomic with respect to updates. update_serialization() computed which agents transitioned under the refcount write lock but applied the serializer enable/disable after releasing it. Two callers could therefore apply their transitions in the opposite order from the refcount mutations that produced them, leaving the serializer enabled at refcount zero. Apply the transitions inside the same refcount write lock, and derive the action from the post-update refcount rather than the caller's `enable` flag. Lock order is refcount -> serializer map -> per-agent serializer in both paths, so they cannot deadlock against each other; neither enable() nor disable() calls back into serializer() or the refcount. This is the protocol already used on the counters branch; both branches now carry identical serializer() and update_serialization() bodies. (cherry picked from commit 6b5b59e)
Already unformatted on the base branch, which fails the Formatting / source check. No functional change. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
spm/tests/queue_hooks_test.cpp built a Queue& by dereferencing a null pointer to reach the hook's early-return path, which clang rejects outright: error: reinterpret_cast from 'std::nullptr_t' to 'rocprofiler::hsa::Queue *' is not allowed The hook never dereferences the queue, so take it as a pointer and let the test pass nullptr. This matches the counters and PC sampling branches. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
… a pointer spm/tests/core.cpp still passed a FakeQueue by reference after the hook was changed to take const hsa::Queue*: error: cannot convert 'rocprofiler::hsa::FakeQueue' to 'const rocprofiler::hsa::Queue*' Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ook test Two errors g++ reports against the libstdc++ headers, so they are easy to miss when scanning diagnostics by source path: error: invalid new-expression of abstract class type 'rocprofiler::hsa::AQLPacket' error: use of deleted function 'rocprofiler::hsa::queue_info_session_t::queue_info_session_t()' AQLPacket is abstract; EmptyAQLPacket is the concrete no-op subclass intended for this. queue_info_session_t holds a Queue& so it has no default constructor, and the hook returns before dereferencing the session, so a null shared_ptr keeps the test free of any HSA runtime. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ity jobs Both workflows failed before compiling any rocprofiler-sdk source. Code coverage died installing ROCR-Runtime with 'CMake 3.25 or higher is required. You are running version 3.22.1', and release compatibility died resolving find_dependency(NUMA) from hsakmt-config.cmake on the 'latest' ROCm container. This branch predates the fixes for both on develop, so take develop's versions of the two workflows and of the rocprofiler-sdk-util action they depend on. The action change is additive -- python-venv-path defaults to empty and is guarded -- so the continuous integration workflow, which does not pass it, is unaffected. The pinned CMake is held at 3.25 rather than develop's 4.x. The external submodules on this branch (json, pybind11, sqlite, yaml-cpp) still declare cmake_minimum_required below 3.5, which CMake 4 rejects outright, so 4.x would trade one configure failure for another. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ility Develop dropped -DROCPROFILER_DISABLE_ATT_QUICK_SCAN=ON because it builds rocprof-trace-decoder, but this branch does not, so rocprofiler-sdk-tool's find_package(rocprof-trace-decoder REQUIRED) fails to configure against every ROCm release container. Restore the flag. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ve-callbacks-spm Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp # projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/CMakeLists.txt
Keeps develop's CMAKE_VERSION_DEB 4.4.3 in the code coverage workflow; the 3.25 pin on the CI-repair side predates this branch merging current develop, whose external submodules no longer declare cmake_minimum_required below 3.5.
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
Contributor
Author
|
Superseded: recreating from the |
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
One or more issues must be addressed before approval.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (2)
What changed in this PR
Migrates SPM dispatch instrumentation from the per-queue callback registry to explicit hooks, with agent-scoped collection and serialization.
Changes:
- Adds explicit SPM enqueue/completion hooks and provenance routing.
- Adds GPU-agent restriction APIs and per-agent serialization refcounting.
- Updates tests, build files, and compatibility workflow.
| File | Description |
|---|---|
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/queue_hooks_test.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/core.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/CMakeLists.txt | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/service.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/queue_hooks.hpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/queue_hooks.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/core.hpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/core.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/CMakeLists.txt | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_hooks/CMakeLists.txt | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_hooks/client_ids.hpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_controller.hpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_controller.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/CMakeLists.txt | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/context/context.hpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/context/context.cpp | Updated as part of this pull request. |
| projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/spm.h | Updated as part of this pull request. |
| .github/workflows/rocprofiler-sdk-rocm_release_compatibility.yml | Updated as part of this pull request. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+313
to
+317
| cfg->dispatch_spm->intersects(*itr->dispatch_spm)) | ||
| { | ||
| // Two SPM dispatch contexts can run concurrently as long as they target disjoint | ||
| // sets of GPU agents. A context with no agent restriction claims every agent. | ||
| return ROCPROFILER_STATUS_ERROR_CONTEXT_CONFLICT; |
Comment on lines
+1223
to
+1224
| // SPM requires per-packet mode; it no longer participates in the registry above. | ||
| if(spm_active) should_batch_packets = false; |
1 task done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Motivation
The purpose of this PR is to isolate the SPM 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. This is independent of the kernel replay feature in PR #7960 but it aids it.
Underlying Problem
Dispatch SPM currently registers a
queue_callbacks_ton every HSA queue. That hides “is this service active?” inside a per-queue map, makes enqueue and completion the same walk, and serializes every GPU while any SPM context is active.This PR:
spm::write_hook,signal_completion_hook,is_any_active).rocprofiler_spm_dispatch_counting_service_set_agents, with GPU drain on stop and per-agent serialization refcounting.The per-queue callback registry remains for counters, thread trace, and PC sampling until those services land in their own PRs.
Notes on Bigger Picture
Aids PR #7960 and the kernel replay work tracked under AIPROFSDK-68. This PR also helps other features that require removing the SPM per-queue callback registry, but does not depend on kernel replay landing first.
Sibling migrations: thread trace (#8790), counter collection (#8891), PC sampling (#8895).
Technical Details
Enter = active, exit = registered. Exit self-filters via
packet_return_mapso in-flight dispatches complete after stop.Permalinks pin to
758072b.Hooks and call sites
is_any_active: queue_hooks.cpp#L103-L107no_real_consumersgate: queue.cpp#L318-L322start_context(noadd_callback): core.cpp#L258-L276enabled→ drain → unserialize): core.cpp#L283-L323intersects: context.cpp#L311-L317set_agentsAPI: spm.h#L318-L338Reviewer Guide
WriteInterceptor(queue.cpp#L318-L322).start_contextdoes not calladd_callback(core.cpp#L258-L276).context::stop_contextstops SPM before the active-slot CAS (context.cpp#L392-L408).spm::stop_contextkeepsqueue_controller_sync(core.cpp#L283-L323) — drain bounds when completions arrive; provenance routing bounds delivery.spm_coreteststop_context_in_flight_completion_routes_via_hook_path(core.cpp#L990+) —packet_return_mapdrains viasignal_completion_hookafter stop.set_agents_restricts_collection, disjoint SPM contexts (core.cpp#L1128+).Questions to Answer:
In-flight SPM dispatch still gets
DISPATCH_END/kfd_stopafter stop?packet_return_mapempty?GPU-1-only SPM leave GPU-0 alone?
Out of scope: deleting
Queue::_callbacks; other service migrations.Issue Tracking
JIRA ticket: AIPROFSDK-1018
Related JIRA ticket on kernel replay: AIPROFSDK-68. The kernel replay PR is #7960.
Test Plan
Test Result
Intended coverage listed above. Treat the Checks tab as source of truth for CI.
Submission Checklist