Files
rocm-systems/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp
T
Ammar ELWazir 987ae3cc47 PC Sampling Support (#715)
* cmake formatting (cmake-format) (#188)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* source formatting (clang-format v11) (#189)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: design of the pc sampling data struct; guarding parts of code that uses ROCr marker packets

* source formatting (clang-format v11) (#191)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* cmake formatting (cmake-format) (#192)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: shadow variable fix

* pcs: fix for compiler errors reported by CI/CD

* source formatting (clang-format v11) (#193)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: docs fix; samples uses rocprofiler::rocprofiler library

* cmake formatting (cmake-format) (#195)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: client in samples folder fixed

* pcs: client requires rocprofiler package as dependency

* pcs: client uses single context

* source formatting (clang-format v11) (#196)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: client using single buffer; no buffer destroy in client

* pcs: client::setup explicitly called from the example

* pcs: rocprofiler_pc_sample_record_t updated

* pcs: fixed init of external correlation id

* source formatting (clang-format v11) (#198)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: remove outdated files; update CMakeLists

* cmake formatting (cmake-format) (#212)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: using rocprofiler_agent_id_t

* pcs: Removing trailing whitespaces

Co-authored-by: Jonathan R. Madsen <jrmadsen@users.noreply.github.com>

* source formatting (clang-format v11) (#214)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: mapping agent_id to the agent

* source formatting (clang-format v11) (#215)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: const while iterating over agents

* source formatting (clang-format v11) (#216)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: calling get_buffer instead of get_buffers

* pcs: workgroup typo

* pcs: documentation for the public PC sampling API

* pcs: queue_cb_t signature adaptation

* pcs: mocks removed

* pcs: updating HsaApiTable with HSA/ROCr PC sampling API

* pcs: querying available PC sampling configs through IOCTL

* pcs: create the PCS session in IOCTL

* pcs: first actual PC samples delivered to the rocprofiler's client :)

* pcs: works with marker packet too

* pcs: using HSA table to call pc sampling related functions

* pcs: using ioctl instead of kfd in naming

* pcs: configuration service test fixed

* pcs: sample processing test fixed

* pcs: marker packet macro wrapper removed

* pcs: marker packet is part of the rocprofiler_packet union

* pcs: one fixme added

* pcs: client that uses pc-sampling and code obj tracing

* pcs: client that supprts PC sampling and code obj tracing refactored

* pcs: show more info for each PC sample

* pcs: hex output for the samples that do not belong to the matmul kernel

* pcs: querying avail configuration happens immediately before configuring

* pcs: hsa_ven_amd_pcs_create_from_id renamed

* pcs: using hsa_stop; accessing a buffer by id from parser

* pcs: includes reworked, tests returned to life

* pcs: rocrofiler dir removed as outdated

* cmake formatting (cmake-format) (#271)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* source formatting (clang-format v11) (#272)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: some warnings fixed

* source formatting (clang-format v11) (#273)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* cmake formatting (cmake-format) (#274)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: show MI200 relevant information in the sample

* pcs: queue cb fixed; rocr.h include fixed

* source formatting (clang-format v11) (#296)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: getting hsa_agent and the doorbell_id from hsa_queue

* source formatting (clang-format v11) (#297)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: correlation ID logic fixed

* source formatting (clang-format v11) (#303)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: pure pc sampling example fixed

* source formatting (clang-format v11) (#307)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* cmake formatting (cmake-format) (#308)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: interval value if the PC sampling is already configured

* pcs: ROCPROFILER_STATUS_ERROR_PC_SAMPLING_ALREADY_CONFIGURED

New status code if another process configured PC sampling service with different configuration.
Samples are extended to consider this case and retry if it happens.

* pcs: hsa_amd_queue_get_info mocked in tests

* source formatting (clang-format v11) (#328)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs (tests): query configs after configuring service

* source formatting (clang-format v11) (#329)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: sample checks workgroup_id_* and wave_id

* source formatting (clang-format v11) (#330)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs samples: running samples on the device 0

* pcs: kfd_ioctl updated

* pcs: ioctl config struct changed fields names

* pcs: status when PC sampling is configured by another process is renamed

* pcs: HSA PC sampling API table fixed

* pcs: tmp hack to be able to use HSA pc sampling table

* source formatting (clang-format v11) (#443)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs service use CIDs generated by HIP API tracing service

* source formatting (clang-format v11) (#455)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* cmake formatting (cmake-format) (#456)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: CID manager

* pcs: explicit flush with no delivered data executes retirement logic

* source formatting (clang-format v11) (#464)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: rocprofiler_query_pc_sampling_agent_configurations docs update

* source formatting (clang-format v11) (#465)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: rocprofiler_configure_pc_sampling_service docs update

* pcs: explicit sync introduced in PCSCIDManager

* pcs: new logic for retiring CIDs in PC sampling service documented

* pcs: queue interception cb signature updated

* source formatting (clang-format v11) (#471)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: if no agents supports PC sampling, fail gracefully

* elaborating when KFD returns EBUSY and EEXIST

* pcs: the second PC sampling examples fails gracefully

* code samples use only single kernel for now

* pcs: CID manager refactored

* source formatting (clang-format v11) (#481)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: ioctl update

* source formatting (clang-format v11) (#531)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs:code sample to test PC sampling applied on concurrent kernels

* source formatting (clang-format v11) (#533)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: pc sampling strest test included

* cmake formatting (cmake-format) (#539)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* source formatting (clang-format v11) (#540)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: standalone benchmark

* cmake formatting (cmake-format) (#555)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: glance in external correlation IDs

* source formatting (clang-format v11) (#557)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* another change in ioctl interface

* pcs: update queue interceptor callbacks and samples accroding to the agent 0 version

* source formatting (clang-format v11) (#611)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: avoid running problematic PC sampling test

* pcs: guarding tests not to fail on architectures not supporting PC sampling

* source formatting (clang-format v11) (#617)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: check IOCTL version prior to each KFD call

* pcs: ioctl refactoring

* pcs: PC sampling service increases the ref_count of the correlation ID of the kernel dispatch

* cmake formatting (cmake-format) (#631)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* source formatting (clang-format v11) (#632)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: PC sampling service provides external correlation IDs

* source formatting (clang-format v11) (#644)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: use rocprofiler_dim3_t for workgrou_ip

* source formatting (clang-format v11) (#645)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: minor fixes

* pcs: updating the documentation for the pc sampling API functions

* pcs: api table and queue controller fix

* pcs: don't generate marker packets for the agent if PC sampling is not configured on it

* pcs: multi-GPU and single-GPU clients

* source formatting (clang-format v11) (#700)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: warning and errors fixed

* source formatting (clang-format v11) (#702)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: clang compiler errors and warnings fixed

* source formatting (clang-format v11) (#716)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: const reference in cid manager

* source formatting (clang-format v11) (#717)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: const & func in manager explicit

* pcs: test to cover creating PC sampling service of agent that does not exist

* pcs: generate marker packets if service is active

* source formatting (clang-format v11) (#719)

Co-authored-by: vlaindic <139573562+vlaindic@users.noreply.github.com>

* pcs: refactoring hsa_adapter; use the correlation_id->thread_idx

* Update source/lib/rocprofiler-sdk/pc_sampling/cid_manager.cpp

* Update source/lib/rocprofiler-sdk/pc_sampling/cid_manager.cpp

* Update source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp

* Update source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp

* Update source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp

* Update source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp

* Update source/lib/rocprofiler-sdk/pc_sampling/utils.cpp

* Update utils.cpp

* moving pc-sampling tests and samples to pc-sampling label

* Format fix

* pcs: use configured instead of active service

* Update source/lib/rocprofiler-sdk/pc_sampling/service.cpp

* pcs: ensure configuring PC sampling on the HSA level is called only once

* pcs: minor fix

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* pcs: refactoring IOCTL integration

* Update source/lib/rocprofiler-sdk/pc_sampling/tests/CMakeLists.txt

Co-authored-by: Ammar ELWazir <ammar.elwazir@amd.com>

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter.cpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter_types.hpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter.cpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter_types.hpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter.hpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* pcs: reverting back what bot doubled

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter_types.hpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* pcs: retesting the bot

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter_types.hpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* pcs: why bot fails on this IOCTL status

* pcs: why failing on <vector>

* Update source/lib/rocprofiler-sdk/pc_sampling/ioctl/ioctl_adapter.cpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* pcs: returning commits removed by bot

* pcs: formatting locally

* pcs: clients are flushing buffers inside the tool_fini

* pcs: sync function in public API

* pcs: sync prior to unloading the code object

* pcs: sync function requires context

* pcs: client uses CID retirement service

* pcs: test for flusing internal ROCr buffers

* pcs: source formatting

* Update source/lib/rocprofiler-sdk/pc_sampling/tests/CMakeLists.txt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* pcs: code samples refactoring

* pcs: public API header refactored

* pcs: rocprofiler_buffer_flush drains internal PC sampling buffers too

* pcs: remove unnecessary functions

* pcs: do not call hsa's copytables

* pcs: include reordering

* pcs: using ROCP_ERROR inside PC sampling implementation

* pcs: pc_sampling sample uses ostream instean of printfs

* pcs: pc_sampling_codeobj tracing using ostream instead of prints

* pcs: registering once for interceptor callbacks

* pcs: do not generate internal CIDs if not in debug mode

* pcs: rebasing fixed; missing external correlation IDs

* pcs: code formatting

* enable kernel tracing service to receive external correlation IDs

* pcs: using ROCPROFILER_STATUS_ERROR_INCOMPATIBLE_KERNEL

* pcs: polishing parser

* formatting

* updating parser to use workgroup_id

* kfd_ioctl.h extracted in details folder

* refactoring

* pcs: preparing to generate code object information

* flush internal buffers prior to unloading code object

* pcs: generating marker records

* pcs: wrap code_object's shutdown function

* ROCR_VISIBLE_DEVICES and HIP_VISISBLE_DEVICES unsupported at the moment

* documenting the ignorance of ROCR/HIP_VISIBLE_DEVICES

* pcs: separate structs for code object loading/unloading markers

* pcs: inst_pkt_t changed the namespace

* pcs: removing wrapper around the shutdown function

* pcs: size in record field

* pcs: documentation refactoring + typdefs

* renaming PCSAgentConfig to PCSAgentSession

* pcs: service does not keep a pointer to the context

* pcs: static assertions related to the versioning

* pcs: rocprofiler_pc_sampling_configuration_t size field

* pcs: report API unimplemented unleass explicitly enabled

* pcs: skip tests if KFD does not support PC sampling

* pcs: if ROCr hides some devices, no PC samples will be delivered for it

* pcs: hip error check after kernel launch

* formatting

* removing PCS info from agent.h

* fix based on review

* Update continuous integration workflow

- use mi200 runner for code coverage (supports PC sampling)
- split sanitizer jobs across navi3, vega20, and mi300

* Updating pc sampling test labels

* ROCP_PC_SAMPLING_ENABLED env in CI

* ROCP_PC_SAMPLING_ENABLED for all CI mi200 jobs

* Rearrange sanitizer assignments

* fixes according to review

* removed unused functions

* pcs: rocprofiler_agent_id_t instead of handle as a key in map

* Update source/lib/rocprofiler-sdk/context/context.hpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* removing drm_fd from the agent.h

* pcs: removing one sample due to complexity

* pcs: refactoring sample

* simplifying sample

* new lines

* Improve queue_control enable intercepter logic

* Update lib/rocprofiler-sdk/hsa/types.hpp

- handle amd_ext size for HSA 1.12.0

* ROCP_PC_SAMPLING_ENABLED -> ROCPROFILER_PC_SAMPLING_BETA_ENABLED

* Update hsa_adapter.cpp

- anonymous namespace + remove debug

* parser update

* Apply suggestions from code review

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>
Co-authored-by: vlaindic <vladimir.indic@amd.com>
Co-authored-by: vlaindic <vlaindic@amd.com>
Co-authored-by: Vladimir Indic <139573562+vlaindic@users.noreply.github.com>
Co-authored-by: Jonathan R. Madsen <jrmadsen@users.noreply.github.com>
Co-authored-by: gobhardw <gopesh.bhardwaj@amd.com>
Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
2024-05-24 09:49:44 -05:00

379 行
16 KiB
C++

// MIT License
//
// Copyright (c) 2023 ROCm Developer Tools
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp"
#include "lib/common/logging.hpp"
#include "lib/rocprofiler-sdk/context/context.hpp"
#include "lib/rocprofiler-sdk/hsa/hsa.hpp"
#include "lib/rocprofiler-sdk/hsa/queue_controller.hpp"
#include "lib/rocprofiler-sdk/pc_sampling/parser/pc_record_interface.hpp"
#include "lib/rocprofiler-sdk/pc_sampling/service.hpp"
#include "lib/rocprofiler-sdk/pc_sampling/types.hpp"
#include "lib/rocprofiler-sdk/pc_sampling/utils.hpp"
#include <hsa/hsa.h>
#include <hsa/hsa_ext_amd.h>
#include <hsa/hsa_ven_amd_pc_sampling.h>
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <stdexcept>
namespace rocprofiler
{
namespace pc_sampling
{
namespace hsa
{
namespace
{
const PCSAgentSession*
get_pcs_session_of(hsa_agent_t hsa_agent)
{
// TODO: optimize this
auto* service = get_configured_pc_sampling_service().load();
for(const auto& [_, agent_session] : service->agent_sessions)
{
if(agent_session->hsa_agent->handle == hsa_agent.handle)
{
return agent_session.get();
}
}
return nullptr;
}
// Called just before the dispatch packet is put inside the real hardware queue.
void
amd_intercept_marker_handler_callback(const struct amd_aql_intercept_marker_s* packet,
hsa_queue_t* queue,
uint64_t packet_id)
{
auto* ext_table_ = rocprofiler::hsa::get_table().amd_ext_;
hsa_agent_t hsa_agent;
if(ext_table_->hsa_amd_queue_get_info_fn(queue, HSA_AMD_QUEUE_INFO_AGENT, &hsa_agent) !=
HSA_STATUS_SUCCESS)
{
throw std::runtime_error("Cannot map hsa_queue_t* to hsa_agent_t");
}
uint64_t doorbell_id = 0;
if(ext_table_->hsa_amd_queue_get_info_fn(queue, HSA_AMD_QUEUE_INFO_DOORBELL_ID, &doorbell_id) !=
HSA_STATUS_SUCCESS)
{
throw std::runtime_error("Cannot map hsa_queue_t* to doorbell_id");
}
auto internal_correlation = packet->user_data[0];
auto external_correlation = rocprofiler_user_data_t{.value = packet->user_data[1]};
auto const* pcs_session = get_pcs_session_of(hsa_agent);
assert(pcs_session);
dispatch_pkt_id_t dispatch_pkt;
dispatch_pkt.type = (pcs_session->method == ROCPROFILER_PC_SAMPLING_METHOD_HOST_TRAP)
? AMD_HOST_TRAP_V1
: AMD_SNAPSHOT_V1;
// Use rocp_agent handle to uniquely identify the GPU device
dispatch_pkt.device = device_handle{static_cast<uint32_t>(pcs_session->agent->id.handle)};
dispatch_pkt.doorbell_id = doorbell_id;
dispatch_pkt.queue_size = queue->size;
dispatch_pkt.write_index = packet_id;
dispatch_pkt.correlation_id = {.internal = internal_correlation,
.external = external_correlation};
auto* parser = pcs_session->parser.get();
if(parser->shouldFlipRocrBuffer(dispatch_pkt))
{
rocprofiler::hsa::get_table().pc_sampling_ext_->hsa_ven_amd_pcs_flush_fn(
pcs_session->hsa_pc_sampling);
}
parser->newDispatch(dispatch_pkt);
}
/**
* Callback called by HSA interceptor when the kernel has completed.
*/
void
kernel_completion_cb(const rocprofiler_agent_t* rocp_agent,
rocprofiler::hsa::rocprofiler_packet& /*kernel_pkt*/,
const rocprofiler::hsa::Queue::queue_info_session_t& session)
{
// No internal correlation IDs, meaning there is no need to call CID manager.
if(!session.correlation_id) return;
// Check if the PC sampling service is configured on this agent.
if(!is_pc_sample_service_configured(rocp_agent->id)) return;
auto* service = get_configured_pc_sampling_service().load();
assert(service);
auto* agent_session = service->agent_sessions.at(rocp_agent->id).get();
// Mark the correlation ID as completed
agent_session->cid_manager->cid_async_activity_completed(session.correlation_id);
}
void
data_ready_callback(void* client_callback_data,
size_t data_size,
size_t lost_sample_count,
hsa_ven_amd_pcs_data_copy_callback_t data_copy_callback,
void* hsa_callback_data)
{
(void) lost_sample_count; // TODO: How is this exposed to the tool?
auto* agent_session = static_cast<pc_sampling::PCSAgentSession*>(client_callback_data);
// Wrap around the logic for copying PC samples from ROCr's buffer to the SDK's
// PC sampling buffer inside the lambda function called by the CID manager,
// a component responsible for managing the PC sampling related part of the
// process of retiring correlation IDs.
agent_session->cid_manager->manage_cids_implicit([&]() {
size_t samples_num = data_size / sizeof(packet_union_t);
// allocate a temporary buffer for copying PC samples
// TODO: think about how to optimize this (e.g., introduce a buffer pool)
auto buff = std::make_unique<packet_union_t[]>(samples_num);
// copy all the data
data_copy_callback(hsa_callback_data, data_size, buff.get());
upcoming_samples_t upc;
// rocp_agent handle uniquely identifies the device
upc.device = device_handle{static_cast<uint32_t>(agent_session->agent->id.handle)};
upc.which_sample_type = (agent_session->method == ROCPROFILER_PC_SAMPLING_METHOD_HOST_TRAP)
? AMD_HOST_TRAP_V1
: AMD_SNAPSHOT_V1;
upc.num_samples = samples_num;
// TODO: how about using std::future
std::condition_variable cv;
auto gfx_major = ((agent_session->agent->gfx_target_version / 10000) % 100);
auto pcs_parser_status = agent_session->parser->parse(
upc, reinterpret_cast<const generic_sample_t*>(buff.get()), gfx_major, cv, false);
if(pcs_parser_status != PCSAMPLE_STATUS_SUCCESS)
{
// TODO: should we end program here or somehow report an error to the user and continue?
throw std::runtime_error("Error while parsing PC samples");
}
});
}
} // namespace
rocprofiler::hsa::rocprofiler_packet
generate_marker_packet_for_kernel(
context::correlation_id* correlation_id,
const tracing::external_correlation_id_map_t& external_correlation_ids)
{
// This function executes for each kernel dispatched to the agent on which
// the PC sampling service is configured.
// By doing this, we allow the following scenario to happen:
// A tool configures PC sampling on an agent and offloads some kernels on that agent.
// In the middle of the kernel execution, a tool starts/activates PC sampling service
// to collect samples. Although the PC sampling service was not started/activated
// at the moment of dispatching kernels, the configured PC sampling service is aware of all
// kernels dispatched on the agent and can recreate their correlation IDs.
// The disadvantage of this approach is that it introduces overhead when PC sampling
// service is inactive/stopped.
amd_aql_intercept_marker_t marker_pkt;
marker_pkt.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC;
marker_pkt.format = AMD_AQL_FORMAT_INTERCEPT_MARKER;
marker_pkt.callback = amd_intercept_marker_handler_callback;
if(correlation_id != nullptr)
{
correlation_id->add_ref_count();
// Use the internal correlation ID generated by the tracing service.
marker_pkt.user_data[0] = correlation_id->internal;
// Find a context that holds PC sampling service.
auto contexts = context::get_registered_contexts(
[](const auto* ctx) { return ctx->pc_sampler != nullptr; });
assert(contexts.size() == 1);
const auto* pcs_context = contexts.at(0);
// Get an external correlation that corresponds to the context
// enclosing PC sampling service.
auto external_corr = tracing::empty_user_data;
auto external_corr_it = external_correlation_ids.find(pcs_context);
if(external_corr_it != external_correlation_ids.end())
external_corr = external_corr_it->second;
marker_pkt.user_data[1] = external_corr.value;
}
else
{
marker_pkt.user_data[0] = 0;
// No external correlation ID
marker_pkt.user_data[1] = 0;
}
return rocprofiler::hsa::rocprofiler_packet(marker_pkt);
}
void
pc_sampling_service_start(context::pc_sampling_service* service)
{
auto* pc_sampling_table_ = rocprofiler::hsa::get_table().pc_sampling_ext_;
for(const auto& [_, agent_session] : service->agent_sessions)
{
// If the agent has been hidden by the ROCR_VISIBLE_DEVICES, no need to start PC sampling.
// Please check `pc_sampling_service_finish_configuration` for more information.
if(!agent_session->hsa_agent.has_value()) continue;
if(pc_sampling_table_->hsa_ven_amd_pcs_start_fn(agent_session->hsa_pc_sampling) !=
HSA_STATUS_SUCCESS)
{
// Two concurrent calls to the pc_sampling::start_service are invoked on the same
// service. The "faster" one succeeds and starts the PC sampling service on the HSA
// level. Although the "slower fails", the service is started.
ROCP_ERROR << "HSA runtime failed to start PC sampling on the agent "
<< agent_session->agent->id.handle << "\n";
}
}
}
void
pc_sampling_service_stop(context::pc_sampling_service* service)
{
auto* pc_sampling_table_ = rocprofiler::hsa::get_table().pc_sampling_ext_;
for(const auto& [_, agent_session] : service->agent_sessions)
{
// If the agent has been hidden by the ROCR_VISIBLE_DEVICES, no need to stop PC sampling.
// Please check `pc_sampling_service_finish_configuration` for more information.
if(!agent_session->hsa_agent.has_value()) continue;
if(pc_sampling_table_->hsa_ven_amd_pcs_stop_fn(agent_session->hsa_pc_sampling) !=
HSA_STATUS_SUCCESS)
{
// Two concurrent calls to the pc_sampling::stop_serivce are invoked on the same
// service. The "faster" one succeeds and stops the PC sampling service on the HSA
// level. Although the "slower fails", the service is stopped. The "slower" continues,
// while the "faster" tries flushing the ROCr's buffer below.
ROCP_ERROR << "HSA runtime failed to stop PC sampling on the agent "
<< agent_session->agent->id.handle << "\n";
continue;
};
// Flush internal PC sampling buffers (ROCr + 2nd level trap handler buffers)
flush_internal_agent_buffers(agent_session.get());
}
}
void
pc_sampling_service_finish_configuration(context::pc_sampling_service* service)
{
// This function is executed once by a single thread.
// No synchronization needed.
auto* pc_sampling_table_ = rocprofiler::hsa::get_table().pc_sampling_ext_;
for(const auto& [_, agent_session] : service->agent_sessions)
{
// Get the HSA agent handle
agent_session->hsa_agent = rocprofiler::agent::get_hsa_agent(agent_session->agent);
// Check if HSA agent corresponding to the KFD node id is hidden via ROCR_VISIBLE_DEVICES,
// If so, we cannot finish the configuration on the ROCr level.
// Consequently, no PC samples will be delivered for this device.
if(!agent_session->hsa_agent.has_value()) continue;
// Create PC sampling session on the ROCr level.
// ROCr reuses IOCTL session with `agent_session->ioctl_pcs_id`.
hsa_status_t status = pc_sampling_table_->hsa_ven_amd_pcs_create_from_id_fn(
agent_session->ioctl_pcs_id,
agent_session->hsa_agent.value(),
pc_sampling::utils::get_matching_hsa_pcs_method(agent_session->method),
pc_sampling::utils::get_matching_hsa_pcs_units(agent_session->unit),
agent_session->interval,
pc_sampling::utils::get_hsa_pcs_latency(),
pc_sampling::utils::get_hsa_pcs_buffer_size(),
data_ready_callback,
agent_session.get(),
&agent_session->hsa_pc_sampling);
if(status != HSA_STATUS_SUCCESS)
{
ROCP_ERROR << "HSA runtime failed to finish configuring PC sampling service"
<< " on the agent with id: " << agent_session->agent->id.handle << "\n";
std::runtime_error("PC sampling config on the HSA/ROCr level failed");
}
// TODO: any better way of informing the parser about what buffer is used for a
// specific agent?
if(!agent_session->parser->register_buffer_for_agent(agent_session->buffer_id,
agent_session->agent->id))
{
std::runtime_error("PCS parser does not accept buffer");
}
}
// Register callbacks for the HSA's queue interceptor.
// TODO: should we store callback ID in the service?
rocprofiler::hsa::get_queue_controller()->add_callback(
std::nullopt,
[](const rocprofiler::hsa::Queue&,
const rocprofiler::hsa::rocprofiler_packet&,
rocprofiler_kernel_id_t /*kernel_id*/,
rocprofiler_dispatch_id_t /*dispatch_id*/,
rocprofiler_user_data_t*,
const rocprofiler::hsa::Queue::queue_info_session_t::external_corr_id_map_t&,
const context::correlation_id*) { return nullptr; },
// Completion CB
[](const rocprofiler::hsa::Queue& q,
rocprofiler::hsa::rocprofiler_packet kern_pkt,
const rocprofiler::hsa::Queue::queue_info_session_t& session,
rocprofiler::hsa::inst_pkt_t&) {
kernel_completion_cb(q.get_agent().get_rocp_agent(), kern_pkt, session);
});
}
rocprofiler_status_t
flush_internal_agent_buffers(const PCSAgentSession* agent_session)
{
// If the agent has been hidden by the ROCR_VISIBLE_DEVICES,
// there is no ROCr internal buffers to flush.
if(!agent_session->hsa_agent.has_value()) return ROCPROFILER_STATUS_SUCCESS;
auto* pc_sampling_table_ = rocprofiler::hsa::get_table().pc_sampling_ext_;
// HSA table has not been loaded, so ROCr buffers does not exist yet.
if(!pc_sampling_table_->hsa_ven_amd_pcs_flush_fn)
return ROCPROFILER_STATUS_ERROR_HSA_NOT_LOADED;
auto hsa_pcs_handle = agent_session->hsa_pc_sampling;
// Explicitly flush ROCr's buffers and sync completed CIDs.
agent_session->cid_manager->manage_cids_explicit([=]() {
// TODO: investigate whether the ROCr should maintain an extra buffer
// beyond the 2nd level trap handler buffers.
if(pc_sampling_table_->hsa_ven_amd_pcs_flush_fn(hsa_pcs_handle) != HSA_STATUS_SUCCESS)
{
// TODO: Think if it is possible to recover from this error.
std::runtime_error("Fail to flush ROCr's buffer explicitly");
}
});
return ROCPROFILER_STATUS_SUCCESS;
}
} // namespace hsa
} // namespace pc_sampling
} // namespace rocprofiler