Skip to content

fix(rocprofiler-sdk): avoid UB and redundant work in the PC sampling completion hook (#8895) - #11871

Merged
amd-vkale merged 4 commits into
users/vkale/remove-callbacks-pc-samplingfrom
users/vlkale/remove-callbacks-pc-sampling-stacked-withcursorfixes
Sep 21, 2026
Merged

amd-vkale merged 4 commits into
users/vkale/remove-callbacks-pc-samplingfrom
users/vlkale/remove-callbacks-pc-sampling-stacked-withcursorfixes

Conversation

@amd-vkale

Copy link
Copy Markdown
Contributor

Motivation

Carries the outstanding review fixes for #8895: one instance of undefined behaviour, two unnecessary costs on the dispatch path, and two pieces of cleanup. Stacked on users/vkale/remove-callbacks-pc-sampling so they land without rewriting that branch's history.

Technical Details

Undefined behaviour in the null-session test

signal_completion_hook took const Queue&, so the unit test covering the "no active session" path had to produce a reference by dereferencing a null pointer. The hook returns before ever touching the queue in that case, so the test passed — but forming the argument is undefined behaviour regardless of whether the callee reads it.

The parameter is now const Queue*. That makes the nullable contract explicit at the signature and lets the test pass nullptr honestly.

Redundant packet copy on every dispatch

kernel_completion_cb took a mutable rocprofiler_packet& that it never modifies, which forced the hook to copy the packet on every completion. It is now const rocprofiler_packet& and the copy is gone.

Configured-agent check in the wrong place

is_pc_sample_service_configured() was checked inside kernel_completion_cb, after the copy above. Every dispatch in the process therefore paid PC sampling's cost whenever any interceptor was active — a regression against the registry path, which cost nothing until a callback was actually registered.

The check moves to the top of the hook, before any work happens. It is dropped from kernel_completion_cb, which has exactly one caller.

Compile gate placement

A reviewer asked why the #if gate lives in the shim rather than inside is_pc_sample_service_configured. It cannot move: service.cpp is not compiled when PC sampling is disabled, whereas queue_hooks.cpp is added before the CMake early-return and therefore always compiles. That constraint is now recorded in a comment instead of being rediscovered by the next reader.

Stale declaration

pc_sampling_internals.hpp still declared kernel_completion_cb(counter_callback_info, ...), a leftover of the registry callback that no longer exists.

Issue Tracking

JIRA ID: AIPROFSDK-1019

Stacked on #8895. Part of the callback-removal series with #8790, #8891 and #8887.

Test Plan

  • pc_sampling/tests/queue_hooks_test.cpp — the null-session case now passes nullptr directly instead of a null reference, exercising the intended path without relying on undefined behaviour.
  • clang-format under the pinned >=11.0.0,<12.0.0.
  • Signature and const-correctness changes were compile-checked in isolation.

Test Result

Static checks pass. The PC sampling tests were not run: the authoring environment has no ROCm install. They need a CI or reviewer run.

Separately, PC sampling's end-to-end behaviour is hardware-dependent and this series has not been run on MI300A. That validation remains outstanding for #8895 as a whole and is not something this PR can supply.

Submission Checklist

… at the shim

Review asked whether the ROCPROFILER_SDK_HSA_PC_SAMPLING guard could move into
is_pc_sample_service_configured instead of living in a separate wrapper. It
cannot: queue_hooks.cpp is added to the object library before the early return
in CMakeLists.txt so it is always built, while service.cpp defines that function
after the early return and is not built when PC sampling is compiled out.
Moving the guard would leave the write interceptor with an undefined symbol in
that configuration.

Record the constraint at the shim so the next reader does not retry the change,
and bump the copyright year on the new files to 2026.

(cherry picked from commit fa38a01)
…completion hook

Three review findings on the completion path:

The hook took the queue by reference, so the unit test covering the null-session
early return had to synthesize one by dereferencing a null pointer. That is
undefined behaviour at argument construction even though the hook returns before
touching the queue. Take the queue by pointer instead, which lets the test pass
nullptr honestly and documents that the callee must not assume a queue exists.

kernel_completion_cb took a mutable reference to a packet it never modifies,
forcing the hook to copy the kernel packet on every completion. Make the
parameter const and drop the copy.

The configured-agent check lived inside kernel_completion_cb, after that copy, so
a process with any interceptor active paid the cost on every dispatch even when
PC sampling was never configured. The registry-based path cost nothing until a
callback was registered. Check is_pc_sample_service_configured in the hook before
doing any work, restoring that property; kernel_completion_cb has one caller, so
the check is not lost.

Also drops a stale kernel_completion_cb declaration in pc_sampling_internals.hpp
that still described the removed registry signature, and corrects two comments
that referred to the old callback mechanism.

(cherry picked from commit c93f8dd)
@amd-vkale
amd-vkale marked this pull request as ready for review September 18, 2026 18:13
@amd-vkale
amd-vkale requested review from a team as code owners September 18, 2026 18:13
@amd-vkale
amd-vkale requested a lite review from Copilot September 18, 2026 18:13
@amd-vkale amd-vkale self-assigned this Sep 18, 2026
@amd-vkale
amd-vkale requested a review from vlaindic September 18, 2026 18:15

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.

🔵 Needs a closer look

PC-sampling tests and hardware-dependent validation were not run.

Pull request overview

Updates PC-sampling completion hooks to remove undefined behavior, redundant packet copies, and unnecessary dispatch-path work.

Changes:

  • Makes queue handling nullable and updates the test.
  • Adds early configuration gating and const-correctness.
  • Removes stale declarations and documents compile-gate placement.
File summaries
File Description
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/queue_hooks_test.cpp Tests null queue handling safely.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/pc_sampling_internals.hpp Removes a stale callback declaration.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.hpp Updates the completion-hook signature.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.cpp Adds early gating and avoids packet copying.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp Applies const-correctness to packet handling.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp Updates callback implementation and comments.
projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp Passes the queue pointer to the completion hook.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0
  • Review effort level: Lite

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

@eble-amd

Copy link
Copy Markdown

signal_completion_hook took const Queue&, so the unit test covering the "no active session" path had to produce a reference by dereferencing a null pointer. The hook returns before ever touching the queue in that case, so the test passed — but forming the argument is undefined behaviour regardless of whether the callee reads it.

The parameter is now const Queue* ...

In case you're interested in the opinion of a detached observer: if I had designed that interface, I'd want to hear a stronger argument before allowing that one test case to dictate the interface. If in production, no caller is expected to pass a null queue pointer, then passing a reference is a good choice, and the test would provide a mock/fake/ad-hoc queue.

…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>
@cursor
cursor Bot requested a review from a team as a code owner September 21, 2026 05:54
@github-actions github-actions Bot added the github actions Pull requests that update GitHub Actions code label Sep 21, 2026
…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>

@vlaindic vlaindic left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

PC sampling part LGTM, please ask someone to verify the CI part.

@amd-vkale
amd-vkale merged commit 301d089 into users/vkale/remove-callbacks-pc-sampling Sep 21, 2026
62 of 70 checks passed
@amd-vkale
amd-vkale deleted the users/vlkale/remove-callbacks-pc-sampling-stacked-withcursorfixes branch September 21, 2026 17:02
amd-vkale added a commit that referenced this pull request Oct 2, 2026
…back registry (#11969)

Stop routing PC sampling kernel completions through the HSA queue
controller's per-queue callback registry. Instead, call
`pc_sampling::kernel_dispatch_phase_exit_hook` explicitly from
`AsyncSignalHandler` in `hsa/queue.cpp`, which forwards to
`kernel_completion_cb` after verifying the service is configured on
the dispatch's agent.

Add `pc_sampling::is_configured_on_agent` to the `no_real_consumers`
gate in `WriteInterceptor`, replacing the notifier count that the old
`add_callback` registration used to bump. This keeps marker-packet
injection alive for PC-sampling-only runs on configured agents.

Both hooks live in a new `queue_hooks.cpp`, added before the
HSA-runtime-version early return in `pc_sampling/CMakeLists.txt` and
guarded internally by `ROCPROFILER_SDK_HSA_PC_SAMPLING`, so they link
as no-ops when HSA PC sampling support is unavailable.

This is completion-only: marker injection stays inline in
`WriteInterceptor`, with no batching or enqueue-hook change. Counters,
thread trace, and SPM keep using the registry until their sibling PRs
land. Hook names follow the series' `kernel_dispatch_phase_*_hook`
convention.

Other changes:
- Move `kernel_completion_cb` out of the anonymous namespace and
  declare it in `hsa_adapter.hpp`; make its `kernel_pkt` param const.
- Correct its comment: it runs on ROCr's async signal handler thread,
  not in the write interceptor.
- Remove `intercept_cb_id` from `PCSAgentSession` (no longer needed).
- Declare `is_hsa_initialized()` in `service.hpp` (was missing).
- Remove stale `kernel_completion_cb` extern from test internals header.
- Add unit tests for unconfigured gate, null-session no-op, and
  seeded-session configured path.

Part of the per-service callback removal series.
* Sibling PRs: #11967 (thread trace), #11968 (SPM), #11970 (counters)
* Combined view: #12135
* Related: #8895, #8586, #8730
* Includes the completion-hook fix reviewed in #11871.


JIRA ID: AIPROFSDK-1019

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github actions Pull requests that update GitHub Actions code organization: ROCm project: rocprofiler-sdk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants