Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
194cdec
refactor(rocprofiler-sdk): migrate SPM off the per-queue callback reg…
amd-vkale Jul 17, 2026
50bc272
fix(rocprofiler-sdk): route SPM completions after stop_context
cursoragent Jul 30, 2026
d9189af
refactor(rocprofiler-sdk): drop the GPU drain from spm::stop_context
cursoragent Jul 30, 2026
53ebf48
docs(rocprofiler-sdk): record what the SPM stop-path fix does and doe…
cursoragent Jul 31, 2026
80e98e0
fix(rocprofiler-sdk): keep the drain in spm::stop_context, per review…
cursoragent Jul 31, 2026
1297d31
fix(spm/tests): destroy counter config before early continue to avoid…
Copilot Aug 18, 2026
01d66a3
fix(rocprofiler-sdk): construct SPM in-flight test correlation_id via…
amd-vkale Aug 18, 2026
cbc6b92
feat(rocprofiler-sdk): scope SPM dispatch collection to agents
cursoragent Aug 10, 2026
996e640
fix(rocprofiler-sdk): repair SPM per-agent scoping CI failures
cursoragent Aug 10, 2026
a8615cf
style(rocprofiler-sdk): clang-format context.cpp stop_context
cursoragent Aug 10, 2026
758072b
fix(rocprofiler-sdk): store effective state in update_serialization; …
Copilot Aug 12, 2026
ee045e3
perf(rocprofiler-sdk): SPM exit-hook fast path and gate caching
cursoragent Aug 19, 2026
8ca1867
test(rocprofiler-sdk): set expected correlation_id in SPM in-flight h…
cursoragent Aug 20, 2026
836d8bc
fix(rocprofiler-sdk): move queue hook tags off the callback registry …
cursoragent Sep 18, 2026
095cbd8
fix(rocprofiler-sdk): close serializer creation and transition-orderi…
cursoragent Sep 18, 2026
c9dc1a7
style(rocprofiler-sdk): apply clang-format to the SPM tests
cursoragent Sep 19, 2026
03c6776
fix(rocprofiler-sdk): take a nullable queue in the SPM completion hook
cursoragent Sep 19, 2026
f5d4844
fix(rocprofiler-sdk): update the remaining SPM hook call site to pass…
cursoragent Sep 19, 2026
f4da004
fix(rocprofiler-sdk): construct valid test fixtures in the SPM exit h…
cursoragent Sep 19, 2026
53c0158
ci(rocprofiler-sdk): repair code coverage and ROCm release compatibil…
cursoragent Sep 21, 2026
965dafd
ci(rocprofiler-sdk): keep ATT quick scan disabled in release compatib…
cursoragent Sep 21, 2026
db0ad92
Merge remote-tracking branch 'upstream/develop' into users/vkale/remo…
amd-vkale Sep 21, 2026
864e1f4
Merge remote-tracking branch 'upstream/develop' into users/vkale/remo…
amd-vkale Sep 21, 2026
878e49d
Merge CI job repairs into users/vkale/remove-callbacks-spm
amd-vkale Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ jobs:
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 10 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 20 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12
python3 -m pip install -U --user -r requirements.txt
# Held at 3.25 rather than the 4.x that requirements.txt resolves to: this
# branch's external submodules (json, pybind11, sqlite, yaml-cpp) still declare
# cmake_minimum_required below 3.5, which CMake 4 rejects outright. This must
# run after requirements.txt so the pin is not upgraded away.
python3 -m pip install -U --user cmake==3.25.0

# Add pip packages to path
echo "$HOME/.local/bin" >> "$GITHUB_PATH"

# Add pip packages to path
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,26 @@ rocprofiler_spm_configure_buffer_dispatch_service(
rocprofiler_spm_dispatch_counting_service_cb_t callback,
void* callback_data_args) ROCPROFILER_API ROCPROFILER_NONNULL(3);

/**
* @brief (experimental) Restrict an SPM dispatch counting service to a set of GPU agents.
*
* By default an SPM dispatch service applies to every GPU agent. This function narrows
* the service so that agents outside @p agents are neither instrumented nor serialized.
* Restricting the agent set also relaxes the SPM context conflict: two contexts may each
* configure an SPM dispatch service and be active at the same time provided their agent
* sets are disjoint.
*
* Must be called after an SPM dispatch service has been configured on @p context_id and
* before the context is started. Passing @p num_agents of zero restores all agents.
*
* @param [in] context_id context id with a configured SPM dispatch service
* @param [in] agents array of GPU agent ids to restrict collection to
* @param [in] num_agents number of entries in @p agents
* @return ::rocprofiler_status_t
*/
ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_status_t
rocprofiler_spm_dispatch_counting_service_set_agents(rocprofiler_context_id_t context_id,
const rocprofiler_agent_id_t* agents,
size_t num_agents) ROCPROFILER_API;

ROCPROFILER_EXTERN_C_FINI
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ get_active_contexts_impl()
}
} // namespace

bool
spm_dispatch_counter_collection_service::intersects(
const spm_dispatch_counter_collection_service& rhs) const
{
if(agents.empty() || rhs.agents.empty()) return true;
const auto& small = (agents.size() < rhs.agents.size()) ? agents : rhs.agents;
const auto& large = (agents.size() < rhs.agents.size()) ? rhs.agents : agents;
for(const auto& agent_id : small)
{
if(large.count(agent_id) > 0) return true;
}
return false;
}

context_array_t&
get_registered_contexts(context_array_t& data, context_filter_t filter)
{
Expand Down Expand Up @@ -295,6 +309,13 @@ start_context(rocprofiler_context_id_t context_id)
// conflicting context
return ROCPROFILER_STATUS_ERROR_CONTEXT_CONFLICT;
}
else if(cfg->dispatch_spm && itr->dispatch_spm &&
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 +313 to +317
}
}

uint64_t rocp_tot_contexts = get_registered_contexts_impl()->size();
Expand Down Expand Up @@ -376,25 +397,29 @@ stop_context(rocprofiler_context_id_t idx)
const context* _expected = itr.load(std::memory_order_acquire);
if(_expected && _expected->context_idx == idx.handle)
{
// Stop queue-interposed services before clearing the active slot so
// disable_serialization() always runs before dispatches stop being instrumented.
// Clearing the slot first opens the opposite window, in which write_hook sees no
// active context and a dispatch is submitted without serializer packets while the
// serializer is still enabled.
if(_expected->dispatch_counter_collection)
{
rocprofiler::counters::stop_context(const_cast<context*>(_expected));
}

if(_expected->dispatch_spm)
rocprofiler::spm::stop_context(const_cast<context*>(_expected));

if(_expected->device_thread_trace) _expected->device_thread_trace->stop_context();
if(_expected->dispatch_thread_trace) _expected->dispatch_thread_trace->stop_context();

bool success = itr.compare_exchange_strong(_expected, nullptr);

if(success)
{
auto nactive = get_num_active_contexts().load(std::memory_order_acquire);
if(nactive > 0) get_num_active_contexts().fetch_sub(1, std::memory_order_release);

if(_expected->dispatch_counter_collection)
{
rocprofiler::counters::stop_context(const_cast<context*>(_expected));
}

if(_expected->dispatch_spm)
rocprofiler::spm::stop_context(const_cast<context*>(_expected));

if(_expected->device_thread_trace) _expected->device_thread_trace->stop_context();
if(_expected->dispatch_thread_trace)
_expected->dispatch_thread_trace->stop_context();

rocprofiler::hsa::queue_interposition::
notify_queue_interposition_consumer_context_stopped(_expected);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@

#include <rocprofiler-sdk/fwd.h>
#include <rocprofiler-sdk/registration.h>
#include <rocprofiler-sdk/cxx/hash.hpp>
#include <rocprofiler-sdk/cxx/operators.hpp>

#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <unordered_map>
#include <unordered_set>

namespace rocprofiler
{
Expand Down Expand Up @@ -94,10 +97,23 @@ struct spm_dispatch_counter_collection_service
// Contains callback information along with other data needed to collect/process
// SPM counters.
std::vector<std::shared_ptr<spm::spm_counter_callback_info>> callbacks{};
// GPU agents this context collects on. An empty set means every GPU agent, which is what a
// plain configure_{buffer,callback}_dispatch call produces;
// rocprofiler_spm_dispatch_counting_service_set_agents narrows it. The set is read on the
// dispatch path and when scoping serialization, so it is fixed at configure time and never
// mutated once the context is started.
std::unordered_set<rocprofiler_agent_id_t> agents{};
// A flag to state whether or not the counter set is currently enabled. This is primarily
// to protect against multithreaded calls to enable a context (and enabling already enabled
// counters).
common::Synchronized<bool> enabled{false};

bool collects_on(rocprofiler_agent_id_t agent_id) const
{
return agents.empty() || agents.count(agent_id) > 0;
}

bool intersects(const spm_dispatch_counter_collection_service& rhs) const;
};

struct device_counting_service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ target_sources(rocprofiler-sdk-object-library PRIVATE ${ROCPROFILER_LIB_HSA_SOUR
${ROCPROFILER_LIB_HSA_HEADERS})

add_subdirectory(details)
add_subdirectory(queue_hooks)
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp"
#include "lib/rocprofiler-sdk/pc_sampling/service.hpp"
#include "lib/rocprofiler-sdk/registration.hpp"
#include "lib/rocprofiler-sdk/spm/queue_hooks.hpp"
#include "lib/rocprofiler-sdk/tracing/tracing.hpp"

#include <rocprofiler-sdk/callback_tracing.h>
Expand Down Expand Up @@ -294,6 +295,15 @@ AsyncSignalHandler(hsa_signal_value_t /*signal_v*/, void* data)
}
});

// SPM completion is migrated off the callback registry (see WriteInterceptor); invoke
// it explicitly here.
spm::signal_completion_hook(&queue_info_session.queue,
packet.kernel_packet,
_session,
packet,
packet.instrumentation_packets,
dispatch_time);

CHECK_NOTNULL(hsa::get_queue_controller())
->serializer(&queue_info_session.queue)
.wlock([&](auto& serializer) {
Expand Down Expand Up @@ -428,8 +438,11 @@ WriteInterceptor(const void* packets,

auto* gls = ::rocprofiler::hip::graph::current_launch_state();
const bool graph_launch_active = (gls != nullptr);
const bool spm_active = spm::is_any_active();
// SPM no longer registers a queue-controller callback, so it does not count toward
// get_notifiers(); detect it explicitly so an SPM-only run still enters the interceptor.
const bool no_real_consumers =
(queue.get_notifiers() == 0 &&
(queue.get_notifiers() == 0 && !spm_active &&
context::get_active_contexts(full_packet_instrumentation_context_filter).empty());

const bool has_kernel_replay = kernel_replay::has_active_replay_contexts();
Expand Down Expand Up @@ -827,6 +840,18 @@ WriteInterceptor(const void* packets,
}
});

// SPM is migrated off the per-queue callback registry: call its hook explicitly
// (the other services still flow through signal_callback above).
spm::write_hook(queue,
kernel_packet,
kernel_id,
dispatch_id,
&_packet_data.user_data,
_packet_data.tracing_data.external_correlation_ids,
corr_id,
_packet_data.instrumentation_packets,
_packet_data.is_serialized);

bool inserted_before = false;
if(_packet_data.is_serialized)
{
Expand Down Expand Up @@ -1195,6 +1220,9 @@ WriteInterceptor(const void* packets,
}
});

// SPM requires per-packet mode; it no longer participates in the registry above.
if(spm_active) should_batch_packets = false;
Comment on lines +1223 to +1224

if(should_batch_packets)
{
ROCP_TRACE_IF(pkt_count > 1) << fmt::format(
Expand Down
Loading
Loading