Repository navigation
Conversation
…ue callback registry 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. Independent of kernel replay. Counter collection 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: - counters::write_hook / signal_completion_hook / is_any_active (new counters/queue_hooks.{hpp,cpp}) iterating active dispatch_counter_collection contexts and calling the existing queue_cb / completed_cb - hsa/queue_hooks/client_ids.hpp: stable inst_pkt producer tags The per-queue callback registry is intentionally retained for thread-trace, pc-sampling and spm; those migrate in follow-up PRs. The callback thread (callback_thread_start/stop) is preserved. The WriteInterceptor gate and should_batch predicate detect counters via is_any_active() (it no longer contributes to queue.get_notifiers()). Removes the now-unused queue_id from counter_callback_info and updates counter tests off iterate_callbacks. Co-authored-by: Cursor <cursoragent@cursor.com>
Address review feedback on #8891: completion routing must use registered contexts (packet_return_map provenance), stop_context must drain in-flight GPU work before deactivation, and queue-interposed services must stop while the context remains active for serialization coordination. Adds queue_hooks regression test for stop-then-complete ordering required by kernel replay (#7960/#8622). Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Reverts the queue_controller_sync() added earlier on this branch. The justification given for it was wrong: it claimed callback_thread_stop() could strand records belonging to dispatches still in flight. It cannot. - consumer_thread_t::exit() sets valid=false, notifies, then waits on the exited flag, and consumer_loop only sets exited once read_ptr == write_ptr, so everything already queued is consumed before the join. counters/tests/ consumer_test.cpp restart already covers this drain-on-exit path. - consumer_thread_t::add() falls back to calling consume_fn inline when valid is false, so a completion arriving after the thread is gone is still processed on the async signal handler thread. Nothing else in counters::stop_context needs an idle GPU. In-flight completions are handled by signal_completion_hook routing over registered rather than active contexts, and the serializer transition is reconciled GPU-side by the hsa_barrier that profiler_serializer::disable() pushes. This aligns the counters path with the same change on the SPM branch, prompted by review feedback from @SrirackshaNag noting that SPM was the only service with a sync in its stop path and that the hook migration removes its original reasons. The context::stop_context ordering is kept but re-justified: 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. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Applies the changes requested in review of the base PR, so that merging this stacked PR clears them on users/vkale/remove-callbacks-counters. Renames, per @vlaindic's comment that 'write' does not convey that this is a write interceptor hook, and per the name agreed in the reply on that thread: counters::write_hook -> counters::kernel_dispatch_phase_enter_hook counters::signal_completion_hook -> counters::kernel_dispatch_phase_exit_hook The exit hook is renamed for symmetry even though only the enter hook was flagged; leaving one half renamed reads worse than either alternative, and the paired names make the enqueue-versus-completion asymmetry this branch introduces easier to follow. is_any_active keeps its name, being neither phase. SPM mirrors these names on its own branch and is deliberately left alone until the review of #8887 settles, so the two branches are briefly inconsistent by choice rather than by oversight. client_ids.hpp: the four constants become an unscoped enum with int64_t as its fixed underlying type. That answers the question asked in review -- the int64_t was not arbitrary, it matches hsa::ClientID, which is how the tag is stored in inst_pkt_t. Unscoped rather than enum class so the implicit conversion to ClientID survives and no emplace site needs a cast. The regression test now constructs the pair piecewise instead of through std::make_pair, which would deduce the tag's enum type and lean on a pair-to-pair conversion; piecewise converts the tag directly and matches the production hook. Copyright headers on the four files the base PR adds move from 2025 to 2026. Verified without a build, which is not available here: clang-format 11.1.0 (the version the repo's .clang-format pins) leaves no unrelated churn, no references to the old names remain, and a standalone translation unit confirms the enum converts to ClientID in both the piecewise and make_pair forms. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
… just unmapped Strengthens the stop-while-in-flight regression test to what the review on #8891 asked for: enqueue kernels, stop the context mid-flight, and assert every kernel produces a record. The previous version had two weaknesses. It passed nullptr for the record callback, so it could not observe delivery at all -- and delivery is the failure the review described. And it drove a single dispatch, which cannot distinguish 'routed the one entry present' from 'routed by provenance'. Now three dispatches are registered while the context is active, the context is stopped while all three are in flight, and completions are fired one at a time. Two independent invariants are checked, because they fail separately: - routing: the map is asserted to drop by exactly one per completion, not merely to reach zero at the end. An aggregate check would pass even if one completion erased another dispatch's entry. - delivery: every dispatch reaches the tool's record callback. Erasure happens in completed_cb before the hand-off to the consumer, so a map-only test would pass even if nothing were ever delivered. The delivery assertion also covers the lifetime condition raised in the review: callback_thread_stop() has already run by then, so these records arrive through the inline path in consumer_thread_t::add() rather than the consumer thread. No kernel executes, so counter values are whatever the profile's output buffer holds; the assertion is about delivery, not values. Not compiled here -- no ROCm toolchain in this environment. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…'s ClientID Captures the non-blocking observation from the review of #8790 at the declaration rather than only in a PR discussion, since that is where someone about to route on these values will look. The tags overlap the per-queue registry's auto-incrementing ClientID, which also starts at 1 and is still in use by the services not yet migrated. This is inert only because no consumer dispatches on the tag: counters' completed_cb and thread trace's post_kernel_call both identify their own packets by pointer lookup or dynamic_cast. The comment states what has to happen before that changes. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ntext Restores the queue_controller_sync() this branch had earlier removed, per review priority: the review of #8891 accepted provenance-based completion routing on the condition that the callback thread and the counter_callback_info objects stay alive until in-flight dispatches drain, and the drain is what makes that hold literally rather than by argument about consumer_thread_t's fallback behaviour. An intermediate revision removed it on the reasoning that consumer_thread_t::exit() drains its queue and add() self-consumes inline afterwards. Both facts are true and they remain a useful backstop, but they are not the guarantee that was asked for -- they argue a late completion is still processed, rather than ensuring there is no late completion to process. The comment now says which is which. Ordering matters and is now stated at the call site: context::stop_context runs this function while the context is still in the active list, so for the duration of the drain the enter hook still reaches queue_cb, whose disabled path returns serialize=true and keeps the serialized->unserialized transition coordinated until disable_serialization() runs. That is what removes the need for a separate draining flag -- and it only works because the drain happens before the active slot is cleared. callback_thread_stop() now runs after the drain rather than alongside it. Not compiled here -- no ROCm toolchain in this environment. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…th drain The comment claimed provenance routing makes stop_context safe without a GPU drain, which contradicts counters::stop_context, where the drain was kept. State what each mechanism actually guarantees: provenance routing delivers a completion that arrives, the drain bounds when completions arrive. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Records how queue-interposed services are wired into dispatch interception after the per-queue callback registry is removed: why the enter hook routes over active contexts while the exit hook routes over registered ones, why that asymmetry is the difference between delivering and dropping the completion of an in-flight dispatch, and why the stop path drains the GPU. Folded in from a separate docs branch so it is reviewed alongside the code it describes. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
… its constructor
context::correlation_id declares constructors, deletes its copy and move, and
holds private ref counters, so it is not an aggregate and a designated
initializer does not compile:
error: initialization of non-aggregate type 'context::correlation_id'
with a designated initializer list
Default-construct and assign the one member the test needs, which leaves every
other member at the same default the designated initializer would have.
This broke the rocprofiler-sdk build, which is why all four Core test jobs and
Code Coverage failed alongside the TheRock package builds.
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…eue interception counters::stop_context() drains in-flight dispatches via queue_controller_sync() and coordinates serializer teardown, both of which require a live queue controller. finalize() ran queue_controller_fini() first and invoked the client finalizers afterwards, so stopping a counter-collection context during teardown operated on destroyed queue state and segfaulted. Also skip empty optional slots when walking the registered-context array; the array is sparse and dereferencing a disengaged optional is undefined. Fixes the hip-streams-per-thread SEGFAULT seen in CI. Co-authored-by: Cursor <cursoragent@cursor.com>
Moving invoke_client_finalizers() ahead of the subsystem teardowns deadlocked OMPT finalization: rocprofv3-test-ompt-tracing and rocprofv3-test-ompt-all timed out on every CI OS, and openmp-tools.test_retired_correlation_ids failed with them. The reorder also did not fix the hip-streams-per-thread SEGFAULT it was meant to address, so revert it and keep the original ordering. The sparse-optional guards in context.cpp are unaffected and stay in place. Co-authored-by: Cursor <cursoragent@cursor.com>
buffered-api-tracing and the two thread-trace-api-triple-buffer tests failed on ubuntu-22.04 only, while rhel-8.8, rhel-9.5 and sles-15.6 passed and TheRock's own rocprofiler-sdk shard passed. No content change; this re-runs CI on an identical tree to confirm. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Dispatch counter collection applied to the whole machine: a context had no notion of which GPUs it collected on, so serialization was enabled on every agent for as long as any counter-collection context was active, and only one such context could be active at all. A tool could decline to profile a dispatch by returning a null config, but that only suppressed instrumentation -- the dispatch was still serialized, which is the part that costs performance and the part the tool had no lever over. The public header has carried a note since the service was introduced saying the agent restriction was unresolved and left to the tool. Store the agent set on the context's counter-collection service and factor it into the three queries that need it: serialization scope at start/stop, the dispatch enter hook, and counter-collection context conflict. An empty set still means every agent, so existing tools are unaffected. Contexts with disjoint agent sets may now be active simultaneously, which is what makes "context A on GPU-0, context B on GPU-1" expressible. Serialization is now reference counted per agent. Counter collection, thread trace and SPM each enable it independently, and without a refcount whichever service stopped first silently unserialized the ones still running. That was a pre-existing bug; scoping serialization per agent makes it reachable more easily, so it is fixed here rather than left behind. Adds rocprofiler_dispatch_counting_service_set_agents() to declare the set. It is rejected while the context is active, since the dispatch path reads the set without a lock and start_context has already used it to scope serialization. Co-authored-by: Cursor <cursoragent@cursor.com>
The previous commit was formatted with clang-format 18 and left the source and cmake format checks failing. CI pins clang-format 11.1.0 and cmake-format 0.6.13, and v18 disagreed with v11 on two spots -- it joined a pre-existing ROCP_ERROR continuation in counters/core.cpp onto one line and moved the extern "C" brace in dispatch_counting_service.cpp -- neither of which this change had any reason to touch. Co-authored-by: Cursor <cursoragent@cursor.com>
…ware The unit tests assert the internal state, which cannot show the property a user actually cares about: that a GPU outside the context's agent set keeps running its streams concurrently. This adds an integration test that measures a multi-stream workload on GPU-0 while a counter collection context is scoped to GPU-1, and fails if GPU-0 gets serialized or instrumented. Machines differ too much for an absolute time to mean anything, so every timing assertion is a ratio against a baseline measured in the same process, and the unrestricted context serves as a positive control -- when it does not visibly serialize the same workload the machine cannot demonstrate stream concurrency and the timing assertions are skipped instead of guessed at. The record and callback assertions are exact and always run. The test reports SKIP and exits 0 below two GPUs. Verified against a deliberately reverted build: without the agent filtering the scoped GPU-0 workload goes from 7.7ms to 32.0ms and three checks fail. Co-authored-by: Cursor <cursoragent@cursor.com>
Suggested by @jrmadsen while reviewing #9868, applied as written: hsa/queue_controller.hpp using agent_handle_set_t = std::unordered_set<rocprofiler_agent_id_t> context/context.hpp std::unordered_set<rocprofiler_agent_id_t> agents{} context/context.hpp return agents.empty() || agents.count(agent_id) > 0 Also pulls in <rocprofiler-sdk/cxx/hash.hpp> and <rocprofiler-sdk/cxx/operators.hpp>, which he noted give full support for using the opaque handles in map/set/uomap/etc. Those includes are what let the sets key on rocprofiler_agent_id_t directly instead of unwrapping to the uint64_t handle. The cascading retyping this implies for the serialization refcounts and their call sites follows in the next commit, so that this one holds only the suggested text. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ects out of line Follows the suggestions applied in the previous commit. Retyping the two agent sets to rocprofiler_agent_id_t leaves the surrounding code still speaking in raw uint64_t handles, so this carries the change through: - serialization_refcount::per_agent keys on rocprofiler_agent_id_t, and count(), enabled() and any() take/iterate the typed id - queue_controller.cpp and counters/core.cpp stop unwrapping to ::handle at the call sites - comments that described the sets as holding rocprofiler_agent_id_t::handle are reworded, since they no longer do Also addresses jrmadsen's fourth review thread, which asked for the body to live in the .cpp: dispatch_counter_collection_service::intersects is now declared in context.hpp and defined in context.cpp. He described that one rather than writing it, so it sits here rather than in his commit. Co-authored-by: Cursor <cursoragent@cursor.com>
Use rocprofiler_agent_id_t values in per_agent_scoping_test serialization calls instead of raw handles, and apply clang-format 11 to queue_controller. Co-authored-by: Cursor <cursoragent@cursor.com>
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
There was a problem hiding this comment.
Pull request overview
Integration preview branch composing multiple in-flight PRs to (1) remove per-queue callback-registry wiring in favor of explicit per-service queue hooks, and (2) introduce experimental kernel replay (multi-pass per-dispatch execution with snapshot/restore) for counter collection, including rocprofv3 CLI/docs and regression tests validating replay behavior and concurrency fixes.
Changes:
- Adds experimental kernel replay callback-tracing domain, memory tracker/snapshot/restore, and localized per-pass context override mechanism.
- Migrates counters, thread trace, PC sampling, and SPM off the per-queue callback registry via explicit
*/queue_hooks.{hpp,cpp}called fromhsa/queue.cpp. - Extends rocprofv3 and output (CSV/JSON) to support kernel replay, and adds new integration/unit tests (including deterministic concurrency regression coverage).
Reviewed changes
Copilot reviewed 84 out of 88 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/rocprofiler-sdk/tests/rocprofv3/kernel-replay/pytest.ini | Adds pytest configuration for kernel replay validation. |
| projects/rocprofiler-sdk/tests/rocprofv3/kernel-replay/conftest.py | Adds pytest CLI options/fixtures for validating replay JSON output structure. |
| projects/rocprofiler-sdk/tests/rocprofv3/kernel-replay/CMakeLists.txt | Adds ctest generate+validate coverage for rocprofv3 kernel replay output and interval regression. |
| projects/rocprofiler-sdk/tests/rocprofv3/CMakeLists.txt | Registers the rocprofv3 kernel replay test directory. |
| projects/rocprofiler-sdk/tests/kernel-replay-concurrency/main.cpp | Adds deterministic workload for kernel replay concurrency regression testing. |
| projects/rocprofiler-sdk/tests/kernel-replay-concurrency/CMakeLists.txt | Builds and registers deterministic kernel replay concurrency integration test. |
| projects/rocprofiler-sdk/tests/kernel-replay-concurrency/client.cpp | Adds LD_PRELOAD tool driving replay/victim opt-out and handshake for deterministic race reproduction. |
| projects/rocprofiler-sdk/tests/CMakeLists.txt | Registers kernel-replay-concurrency tests in the overall test suite. |
| projects/rocprofiler-sdk/tests/bin/kernel-replay/CMakeLists.txt | Adds HIP test binary used by rocprofv3 kernel replay integration tests. |
| projects/rocprofiler-sdk/tests/bin/CMakeLists.txt | Registers the kernel-replay test binary. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/thread_trace/tests/queue_hooks_test.cpp | Adds unit test for thread-trace queue hook activeness predicate. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/thread_trace/tests/CMakeLists.txt | Builds/registers thread-trace queue-hooks unit test. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/thread_trace/queue_hooks.hpp | Introduces explicit thread-trace write/completion hooks and activeness check. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/thread_trace/queue_hooks.cpp | Implements thread-trace explicit queue hooks. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/thread_trace/core.cpp | Removes queue-controller registration and adds replay-local override gating in pre-kernel hook. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/thread_trace/CMakeLists.txt | Adds thread-trace queue hook sources/headers to build. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/queue_hooks_test.cpp | Adds unit test for SPM queue hook activeness predicate. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/core.cpp | Updates SPM unit tests to stop asserting callback-registry state. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/tests/CMakeLists.txt | Adds SPM queue hook test source. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/queue_hooks.hpp | Introduces explicit SPM write/completion hooks and activeness check. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/queue_hooks.cpp | Implements SPM explicit queue hooks. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/core.hpp | Removes stored per-queue callback ClientID from SPM callback info. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/core.cpp | Removes queue-controller callback registration/removal; relies on explicit hooks. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/spm/CMakeLists.txt | Adds SPM queue hook sources/headers to build. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/registration.cpp | Installs kernel replay memory tracker wrappers and includes replay in queue-interposition gating. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/types.hpp | Removes unused queue interceptor ClientID field. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/queue_hooks_test.cpp | Adds unit test for PC sampling agent-configuration predicate. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/CMakeLists.txt | Adds PC sampling queue hook test source. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.hpp | Introduces always-linkable PC sampling hooks/predicates. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.cpp | Implements always-linkable PC sampling predicates and explicit completion hook. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp | Exposes PC sampling kernel completion entry point for explicit hook call. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp | Removes callback registration; routes completion via explicit hook. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/CMakeLists.txt | Ensures queue_hooks builds even when PC sampling HSA support is unavailable. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/utils.hpp | Adds shared allocation-classification helper API for tracker/tests. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/utils.cpp | Implements allocation classification via pointer-info query. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/tests/snap_kernels.hpp | Declares host-callable wrappers around HIP test kernels for snapshot/restore tests. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/tests/snap_kernels.cpp | Implements HIP kernels used by snapshot/restore tests. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/tests/memory_tracker_test.cpp | Adds host-only tests for tracker install gating and inventory behavior. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/tests/memory_snapshot_test.cpp | Adds host-only tests for snapshot ok/empty/restore gating contract. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/tests/local_context_test.cpp | Adds unit tests for replay-local per-pass context override semantics. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/tests/CMakeLists.txt | Builds/registers kernel replay unit tests and manages GPU resource locking. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/replay_callbacks.hpp | Declares kernel replay callback execution and replay-plan structures. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/memory_tracker.hpp | Declares replay memory allocation inventory and HSA table wrapper installers. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/memory_tracker.cpp | Implements allocation tracking wrappers, inventory, and executable/kernarg exclusions. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/memory_snapshot.hpp | Declares minimal device memory snapshot/restore structures and contract. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/local_context.hpp | Declares replay-local per-pass context override mechanism. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/local_context.cpp | Implements thread-local loop-scoped override map and arm-window enforcement. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/kernel_replay.hpp | Declares enum-to-string utilities for kernel replay operations. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/kernel_replay.cpp | Implements enum-to-string utilities for kernel replay operations. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/kernel_replay/CMakeLists.txt | Adds kernel replay sources/headers and tests to build. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.hpp | Changes Queue::sync() API to return a drain-success boolean for replay/teardown behavior. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_hooks/CMakeLists.txt | Adds header-only client-id tags build target wiring. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_hooks/client_ids.hpp | Introduces stable inst-packet producer tags for explicit hooks. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue_controller.cpp | Ensures queue interposition stays enabled when kernel replay tracing is configured. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/CMakeLists.txt | Registers the new hsa/queue_hooks subdirectory. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/tests/core.cpp | Updates counter tests to stop relying on callback registry state. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/tests/CMakeLists.txt | Adds counters queue hook test source. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/queue_hooks.hpp | Introduces explicit counters enter/exit hooks and activeness check. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/queue_hooks.cpp | Implements explicit counters queue hooks, including registered-context completion routing. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/dispatch_handlers.cpp | Adds replay-local context override gating into counters dispatch path. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/core.hpp | Removes stored per-queue callback ClientID from counters callback info. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/core.cpp | Removes per-queue callback registration/removal and tightens drain/teardown ordering. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/CMakeLists.txt | Adds counters queue hook sources/headers to build. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/context/context.cpp | Stops queue-interposed services before clearing active slot (serialization ordering fix). |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/CMakeLists.txt | Registers new kernel_replay subdirectory in SDK library build. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/callback_tracing.cpp | Adds KERNEL_REPLAY callback-tracing kind integration and enables tracker/replay service gate. |
| projects/rocprofiler-sdk/source/lib/rocprofiler-sdk-tool/config.hpp | Adds kernel replay config flag (currently conflicting with base output_config member). |
| projects/rocprofiler-sdk/source/lib/output/output_config.hpp | Adds kernel replay field to output config serialization. |
| projects/rocprofiler-sdk/source/lib/output/output_config.cpp | Parses ROCPROF_KERNEL_REPLAY into output config. |
| projects/rocprofiler-sdk/source/lib/output/generateCSV.cpp | Adds optional Replay_Pass column emission and replay-specific CSV encoder. |
| projects/rocprofiler-sdk/source/lib/output/csv.hpp | Adds counter_collection_replay_csv_encoder type alias. |
| projects/rocprofiler-sdk/source/lib/output/counter_info.hpp | Adds per-record replay pass index to counter records and serialization. |
| projects/rocprofiler-sdk/source/include/rocprofiler-sdk/fwd.h | Adds KERNEL_REPLAY callback-tracing kind and kernel replay operation enum. |
| projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/kernel_replay.h | Adds experimental public API payload struct for kernel replay callbacks and localized context control. |
| projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/CMakeLists.txt | Installs the new experimental kernel replay header. |
| projects/rocprofiler-sdk/source/include/rocprofiler-sdk/cxx/enum_string.hpp | Adds enum-string metadata and static asserts for new kernel replay kind/operations. |
| projects/rocprofiler-sdk/source/docs/how-to/using-rocprofv3.rst | Documents rocprofv3 kernel replay beta flag behavior and constraints. |
| projects/rocprofiler-sdk/source/docs/conceptual/queue_hooks/queue_callback_removal_architecture.md | Adds conceptual architecture doc for callback registry removal and routing/teardown invariants. |
| projects/rocprofiler-sdk/source/bin/rocprofv3.py | Adds --kernel-replay-beta-enabled CLI flag, validation, and env/config merging logic. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // Route counter collection through in-process kernel replay: collect every --pmc counter group | ||
| // in a single application run by replaying each dispatch once per group (device-memory | ||
| // snapshot/restore between passes). The pass count is the number of counter groups. | ||
| bool kernel_replay = get_env("ROCPROF_KERNEL_REPLAY", false); | ||
|
|
There was a problem hiding this comment.
@copilot Fix the code for all comments in this review comment.
When a review comment includes a suggested change, apply the suggestion exactly.
Do not make changes beyond what is described in the linked review comment.
There was a problem hiding this comment.
Fixed in the latest commit. Removed kernel_replay from the derived config struct (lines 158–162) and its CFG_SERIALIZE_MEMBER entry from config::save(). The base output_config already declares the field (initialized to false), already reads it from ROCPROF_KERNEL_REPLAY in parse_env() (called by load_from_env() which the config constructor invokes), and already serializes it — so there is now a single source of truth.
| plan.user_data = plan.config_contexts.empty() ? tracing::empty_user_data | ||
| : plan.config_contexts.front().user_data; |
There was a problem hiding this comment.
@copilot Fix the code for all comments in this review comment.
When a review comment includes a suggested change, apply the suggestion exactly.
Do not make changes beyond what is described in the linked review comment.
Please add pertinent tests and comment changes.
There was a problem hiding this comment.
Fixed in the latest commit. Changed config_contexts.front() to config_contexts.back() so that user_data is taken from the same last-registered context as pass_count_cb (which comes from the shared config_data payload under last-writer-wins semantics). Added an explanatory comment at the fix site in replay_callbacks.cpp. Added replay_plan_test.cpp with three host-only unit tests (single_context_uses_that_context, multiple_contexts_uses_last_not_first, empty_contexts_gives_empty_user_data) that validate the selection invariant directly on callback_context_data_vec_t without requiring the HSA or rocprofiler runtime; registered the new target kernel-replay-plan-test in CMakeLists.txt.
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…eplay integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…y integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>
… integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…play integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
CI's black --required-version 26 collapses a few call-argument wraps that black 25 left alone. Matches the python (3.10) check on the integration preview. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
… the kernel replay integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
# Conflicts: # projects/rocprofiler-sdk/CHANGELOG.md Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com> # Conflicts: # projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/sample_processing.cpp
…n its own rocprofv3 already fails when --replay-mode kernel arrives without --kernel-replay-beta-enabled, but not the other way round. The flag's name reads as if it enabled replay, so a command line carrying only the acknowledgement ran application replay while the user believed they were running kernel replay, and the counter values application replay produces are indistinguishable from replayed ones. Fail with a diagnostic that names --replay-mode kernel instead. An input file job may be the thing asking for replay, and the acknowledgement can only be given on the command line, so the check only fires when nothing anywhere selected kernel replay. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: amd-vkale <291155109+amd-vkale@users.noreply.github.com>
Co-authored-by: amd-vkale <291155109+amd-vkale@users.noreply.github.com>
Bring the range replay service up to date with develop so review and CI run against the current rocprofiler-sdk, including the replay drain helpers that now live in hsa/replay_window. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
These tests abort while acquiring a KFD thread on navi4, the same failure kernel replay already skips. Tracking issue: #13606. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Packet replay leaves the host stack where it is. A tool that needs the host code inside the range to run again sets host_replay, and the application arms sigsetjmp in its own frame so the jump target is still live when the range closes. Co-authored-by: Cursor <cursoragent@cursor.com>
…ket recorder Host replay (tool sets host_replay at CONFIG, application opens the range with ROCPROFILER_RANGE_REPLAY_HOST_BEGIN) no longer rides on the packet recording. Nothing is recorded: end() fences every GPU queue, restores device memory on every GPU agent plus registered host memory, and siglongjmps back so the application's own code re-runs per pass. - Copies, memsets, multiple queues/agents, graph launches and balanced allocations inside the range no longer decline; other-thread dispatches and device writes still do, on any agent. - New rocprofiler_range_replay_host_track_memory() and rocprofiler_range_replay_get_host_pass(). - HOST_BEGIN is now a statement with sigsetjmp as the whole if condition (the ternary form was undefined behaviour); host_jmpbuf() returns void* so the header stays usable from strict ISO C; begin() consumes the arming so a stale jmp_buf is never a target. - The local-context override is heap-owned for the life of the range so PASS toggles apply to the application's re-executed dispatches. - No exit snapshot: the last pass re-ran the host code too, so host and device state stay consistent. VERIFY compares the last pass with pass 0. - GPU-free unit tests (range-replay-host-replay-test) and ABI/C checks for the new field and the macro. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…ing position '!host_replay || sigsetjmp(...) == 0' is not one of the contexts ISO C allows sigsetjmp in. Open the range in separate branches and make the status written after the jump target volatile. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
One range around a time-stepping solver: FFT, spectral filter, inverse FFT, 5-point stencil and Jacobi sweeps on two streams joined by events, with D2D copies, memsets, a D2H residual reduced on the host and a host-computed boundary row copied back each step. Variants add a graph launch and a scratch hipMalloc/hipFree per step, a continue-callback pass count and a local counter stop; negative variants check that packet replay and an unarmed application decline. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com>
The formatting workflow sorts cstdlib after cstdint in the range replay sample client, and rewraps two CMake comments the 0.6.13 line width rejects. Co-authored-by: Vivek Kale <vivek.kale@amd.com>
Co-authored-by: Vivek Kale <vivek.kale@amd.com> # Conflicts: # projects/rocprofiler-sdk/CHANGELOG.md
…current heads into the kernel replay integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>
…to the kernel replay integration Co-authored-by: Vivek Kale <vivek.kale@amd.com>



What this is
An integration preview, not a merge candidate. It composes
developwith the current heads ofthe four callback-removal PRs so that the kernel replay service can be exercised against all four
migrated subsystems at once. Each dependency is reviewed and merged on its own PR; this branch
exists only to show that they compose and that replay still works on top of the composition.
This must not merge, and must not merge ahead of its dependencies. Apart from merge-conflict
resolutions it carries no content of its own.
Composition
Merged onto
develop, in this order:users/vkale/remove-callbacks-counters--with-cursor-fixesusers/vkale/remove-callbacks-thread-trace--with-cursor-fixesusers/vkale/remove-callbacks-pc-sampling--with-cursor-fixesusers/vkale/remove-callbacks-spm--with-cursor-fixesThe kernel replay service is no longer carried on this branch. #7960 and #10439 are already merged
into
develop, so replay arrives with the base and is now newer here than the version this branchused to carry.
Why it was recomposed rather than rebased
The previous revision merged the older fork-hosted PRs (#8891, #8790, #8895, #8887) against an
August
develop. Since then the thread trace and SPM work merged into their--with-cursor-fixesbranches, those branches were rebased onto a later
develop, and the kernel replay service landedin
develop. The merge bases this branch relied on no longer exist, so it was rebuilt from thecurrent heads instead of rebased.
#8891 and #8895 are deliberately left untouched as review-history records. Their live equivalents
are #11970 and #11969.
Conflict resolutions
Every conflict was the same shape: two subsystems independently migrating the same call site off
the per-queue callback registry. All were resolved as unions, never by taking one side.
hsa/queue.cpp— every subsystem's explicit enter and exit hook is invoked at the call sites theregistry used to drive. The interception gate and the per-packet-mode gate AND together every
subsystem's per-agent predicate, so a run using only one of them still intercepts, and queues on
agents no service is configured for stay on the fast path.
context/context.cpp— the context-registry snapshot rework appears exactly once; it is identicalon the three branches that carry it. The
start_contextconflict cascade keeps each service's ownagent-disjointness clause rather than the unconditional check it replaced.
thread_trace/core.cpp—resource_deinit()andpost_kernel_call()take the migrated threadtrace versions, so a completion that races teardown is delivered through the reference the packet
carries instead of a lookup in a map that teardown may already have cleared.
What the committed tests assert
ThreadTraceQueueHooks.CompletionAfterResourceDeinitStillDrainsasserts that a thread tracecompletion arriving after
resource_deinit()is still drained rather than dropped.unit.counters_per_agent.disjoint_agent_contexts_can_be_active_togetherandoverlapping_agent_contexts_still_conflict, with the equivalent thread trace and SPM cases,assert that contexts scoped to disjoint agent sets coexist while overlapping ones still conflict.
test-kernel-replay-local-context-*integration tests exercise replay against countercollection, thread trace, SPM and PC sampling, including stop-and-restart sequences.
rocprofv3-test-kernel-replay-validateasserts the replay pass column covers every pass exactlyonce per
dispatch_id.The SPM integration tests remain
set(IS_DISABLED True)per the SPM owner's decision; that file isuntouched on this branch.
What this is
An integration preview, not a merge candidate. It composes
developwith the open kernel replay product PRs so they can be exercised together:sigsetjmp/siglongjmp(feat(rocprofiler-sdk): host range replay (sigsetjmp/siglongjmp) — re-run the application's code per pass #15289)Each dependency is reviewed and merged on its own PR; this branch exists only to show that they compose.
This must not merge, and must not merge ahead of its dependencies. Apart from merge-conflict resolutions it carries no content of its own.
Range replay: two ways to re-execute a range
Kernel replay re-submits one dispatch per pass and is unchanged here. For a range of work, this preview now carries both re-execution paths. The tool picks one per range with
host_replayon the CONFIG record.end()restores state and callssiglongjmpto the app'ssigsetjmp; the app's own code runs againbegin()/end()ROCPROFILER_RANGE_REPLAY_HOST_BEGINmacro,track_memoryfor host stateMULTI_QUEUE,MULTI_AGENT,MEMORY_COPY_IN_RANGE,GRAPH_LAUNCH, ...)flowchart LR subgraph PKT["Packet replay"] P1["app: begin, kernels on one stream, end"] --> P2["interceptor records packets"] --> P3["executor re-submits per pass"] P2 -.->|"copy, graph, 2nd stream/GPU"| P4["decline, run once"] end subgraph HST["Host replay"] H1["app: HOST_BEGIN (sigsetjmp)"] --> H2["app code: streams, copies, graphs, host math"] --> H3["end: fence all GPUs, restore"] H3 -->|"siglongjmp per pass"| H1 endThe application contract follows from ISO C setjmp rules (
longjmprestores registers, not memory, and skips destructors). The full before/after system software diagram is in #15289.Composition (current head)
Merged onto
develop, in this order:users/vkale/range-replay-v1733091ace5c(via #15289)cursor/range-replay-host-setjmp-fa02219a133ccad__hip_cuid_*, retained staging)users/vkale/kr-perf-5-retained-staging--with-cursor-helpusers/vkale/kr-perf-0-replay-benchmark-harness--with-cursor-helpusers/vkale/kr-perf-1-skip-constant-symbols--with-cursor-help--kernel-replay-beta-enabledrequires--replay-mode kernelusers/vkale/kernel-replay-beta-flag-with-cursor-fixes-help8813caeb296Not on this preview
hsa/queue.cpp,kernel_replay/memory_snapshot.{hpp,cpp}). Needs a dedicated compose before it can land here.CHANGELOG.md, docs TOC/index,rocpd/features.py,versions.yml. Needs a rebase onto this tip.CMakeLists.txt. Its check also needs a host-mode rule: under host replay, a pointer into a region registered withtrack_memoryis restored and should not decline.Other kernel replay adjacent PRs that are not part of this composition: #13083 / #13168 (pass-toggle experiments), #12776 / #12729 (ATT/JSON pass tooling), #12888 (serial test runner), #13164 (rocpd repeated PMC), #14928 (PC sampling per pass). The weekly range replay test stack (#12815 → #13272 → #13744 → #14259 → #14806) sits on #10864's packet path. #12815 was closed by the stale bot on 2026-11-05.
Conflict resolutions on this refresh
CHANGELOG.mdwhen mergingdevelop: both sides added a### Resolved issuesentry; kept both.No other conflicts. #15289 and #11432 merged cleanly.
Verification on this refresh
therock-dist-linux-gfx94X-dcgpu-10.1.0a20260822,ROCM_VERSION_MAJOR10, gcc 13 for host code,GPU_TARGETS=gfx942, tests and samples on): 1216 of 1216 targets, no warnings.host-replay15,abi27,range-state18,executor16,phases10,digest7,configure6,retained-kernarg6,queue-hooks2; kernel replayabi22,local-context10,staging6,phases3,configure1.kernel-replay-snapshot-testneeds a GPU and ran 0 cases.tests/range-replay-host, run in this PR's CI.Sync cadence
Refreshed by hand on 2026-11-06. The every-other-day timer that used to merge the carried heads no longer exists. New conflicts abort the offending merge and are reported instead of guessed.
What the committed tests assert
--replay-mode kernelgating from fix(rocprofiler-sdk): reject --kernel-replay-beta-enabled without --replay-mode kernel #11432.