[RSERP-1802] Add trace decoder to API (#398)

* Add trace decoder to API.

* Cleanup and activity

* Rename

* Minor fix

* Replace tt/TT with thread_trace/THREAD_TRACE

- public API types are not abbreviated

* Fix aliases

* Build system updates

- activate clang-tidy for all subfolders in lib
- fix addition of sources for att-tool

* Fix clang-tidy issues with lib/att-tool/counters.{hpp,cpp}

* Delete counters.cpp

* Formatting

---------

Co-authored-by: Giovanni Baraldi <gbaraldi@amd.com>
Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
This commit is contained in:
Baraldi, Giovanni
2025-05-17 21:08:33 +02:00
کامیت شده توسط GitHub
والد 3eb921a34c
کامیت 65786f619d
56فایلهای تغییر یافته به همراه1175 افزوده شده و 1419 حذف شده
@@ -1,5 +1,7 @@
set(ROCPROFILER_LIB_THREAD_TRACE_SOURCES att_core.cpp att_service.cpp code_object.cpp)
set(ROCPROFILER_LIB_THREAD_TRACE_HEADERS att_core.hpp code_object.hpp)
set(ROCPROFILER_LIB_THREAD_TRACE_SOURCES core.cpp service.cpp code_object.cpp decode.cpp
dl.cpp)
set(ROCPROFILER_LIB_THREAD_TRACE_HEADERS core.hpp code_object.hpp dl.hpp
trace_decoder_api.h)
target_sources(
rocprofiler-sdk-object-library PRIVATE ${ROCPROFILER_LIB_THREAD_TRACE_SOURCES}
${ROCPROFILER_LIB_THREAD_TRACE_HEADERS})
@@ -62,9 +62,9 @@ constexpr uint64_t MAX_BUFFER_SIZE = std::numeric_limits<int32_t>::max(); // aq
struct cbdata_t
{
rocprofiler_agent_id_t agent;
rocprofiler_att_shader_data_callback_t cb_fn;
const rocprofiler_user_data_t* userdata;
rocprofiler_agent_id_t agent;
rocprofiler_thread_trace_shader_data_callback_t cb_fn;
const rocprofiler_user_data_t* userdata;
};
common::Synchronized<std::optional<int64_t>> client;
@@ -349,7 +349,8 @@ DispatchThreadTracer::pre_kernel_call(const hsa::Queue& queue,
parameters.callback_userdata.ptr,
user_data);
if(control_flags == ROCPROFILER_ATT_CONTROL_NONE) return {nullptr, parameters.bSerialize};
if(control_flags == ROCPROFILER_THREAD_TRACE_CONTROL_NONE)
return {nullptr, parameters.bSerialize};
auto packet = agent.get_control(true);
post_move_data.fetch_add(1);
@@ -56,10 +56,10 @@ namespace thread_trace
{
struct thread_trace_parameter_pack
{
rocprofiler_context_id_t context_id{0};
rocprofiler_att_dispatch_callback_t dispatch_cb_fn{nullptr};
rocprofiler_att_shader_data_callback_t shader_cb_fn{nullptr};
rocprofiler_user_data_t callback_userdata{};
rocprofiler_context_id_t context_id{0};
rocprofiler_thread_trace_dispatch_callback_t dispatch_cb_fn{nullptr};
rocprofiler_thread_trace_shader_data_callback_t shader_cb_fn{nullptr};
rocprofiler_user_data_t callback_userdata{};
// Parameters
uint8_t target_cu = 1;
@@ -0,0 +1,253 @@
// MIT License
//
// Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// 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/common/static_object.hpp"
#include "lib/rocprofiler-sdk/aql/helpers.hpp"
#include "lib/rocprofiler-sdk/context/context.hpp"
#include "lib/rocprofiler-sdk/hsa/agent_cache.hpp"
#include "lib/rocprofiler-sdk/registration.hpp"
#include "lib/rocprofiler-sdk/thread_trace/dl.hpp"
#include <rocprofiler-sdk/experimental/thread-trace/trace_decoder.h>
#include <rocprofiler-sdk/experimental/thread_trace.h>
#include <glog/logging.h>
#include <cstdint>
namespace
{
using DL = rocprofiler::thread_trace::DL;
using AddressTable = rocprofiler::sdk::codeobj::disassembly::CodeobjAddressTranslate;
class DecoderInstance
{
public:
DecoderInstance(std::unique_ptr<DL> _dl)
: dl(std::move(_dl))
{}
std::unique_ptr<DL> dl{nullptr};
AddressTable table{};
};
std::mutex map_mut;
auto&
get_dlopens()
{
static auto*& _v = rocprofiler::common::static_object<
std::unordered_map<uint64_t, std::shared_ptr<DecoderInstance>>>::construct();
return *CHECK_NOTNULL(_v);
}
std::shared_ptr<DecoderInstance>
get_dl(rocprofiler_thread_trace_decoder_handle_t handle)
{
auto lk = std::unique_lock{map_mut};
auto it = get_dlopens().find(handle.handle);
if(it == get_dlopens().end()) return nullptr;
return it->second;
}
} // namespace
extern "C" {
rocprofiler_status_t
rocprofiler_thread_trace_decoder_create(rocprofiler_thread_trace_decoder_handle_t* handle,
const char* path)
{
auto dl = std::make_unique<DL>(path);
if(dl->handle == nullptr) return ROCPROFILER_STATUS_ERROR_NOT_AVAILABLE;
if(!dl->valid()) return ROCPROFILER_STATUS_ERROR_INCOMPATIBLE_ABI;
auto lk = std::unique_lock{map_mut};
static uint64_t count = 1;
auto instance = std::make_shared<DecoderInstance>(std::move(dl));
handle->handle = count++;
get_dlopens()[handle->handle] = std::move(instance);
return ROCPROFILER_STATUS_SUCCESS;
}
void
rocprofiler_thread_trace_decoder_destroy(rocprofiler_thread_trace_decoder_handle_t handle)
{
auto lk = std::unique_lock{map_mut};
get_dlopens().erase(handle.handle);
}
rocprofiler_status_t
rocprofiler_thread_trace_decoder_codeobj_load(rocprofiler_thread_trace_decoder_handle_t handle,
uint64_t load_id,
uint64_t load_addr,
uint64_t load_size,
const void* data,
uint64_t size)
{
auto decoder = get_dl(handle);
if(decoder == nullptr) return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
try
{
decoder->table.addDecoder(data, size, load_id, load_addr, load_size);
} catch(...)
{
return ROCPROFILER_STATUS_ERROR;
}
return ROCPROFILER_STATUS_SUCCESS;
}
rocprofiler_status_t
rocprofiler_thread_trace_decoder_codeobj_unload(rocprofiler_thread_trace_decoder_handle_t handle,
uint64_t load_id)
{
auto decoder = get_dl(handle);
if(decoder == nullptr) return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
try
{
if(decoder->table.removeDecoder(load_id)) return ROCPROFILER_STATUS_SUCCESS;
} catch(std::exception&)
{}
return ROCPROFILER_STATUS_ERROR;
}
}
namespace
{
using Instruction = rocprofiler::sdk::codeobj::disassembly::Instruction;
using SymbolInfo = rocprofiler::sdk::codeobj::disassembly::SymbolInfo;
struct trace_data_t
{
uint8_t* data{nullptr};
uint64_t size{0};
std::shared_ptr<DecoderInstance> decoder{nullptr};
rocprofiler_thread_trace_decoder_callback_t cb{nullptr};
void* userdata{nullptr};
};
uint64_t
copy_trace_data(uint8_t** buffer, uint64_t* buffer_size, void* userdata)
{
trace_data_t& data = *reinterpret_cast<trace_data_t*>(userdata);
*buffer_size = data.size;
*buffer = data.data;
data.size = 0;
return *buffer_size;
}
rocprofiler_thread_trace_decoder_status_t
isa_callback(char* isa_instruction,
uint64_t* isa_memory_size,
uint64_t* isa_size,
rocprofiler_thread_trace_decoder_pc_t pc,
void* userdata)
{
ROCP_FATAL_IF(userdata == nullptr) << "Userdata is null!";
auto& table = static_cast<trace_data_t*>(userdata)->decoder->table;
std::unique_ptr<Instruction> instruction{nullptr};
try
{
instruction = table.get(pc.marker_id, pc.addr);
} catch(std::exception& e)
{
ROCP_WARNING << pc.marker_id << ":" << pc.addr << ' ' << e.what();
return ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR;
}
if(!instruction) return ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_ARGUMENT;
{
size_t tmp_isa_size = *isa_size;
*isa_size = instruction->inst.size();
if(*isa_size > tmp_isa_size)
return ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES;
}
memcpy(isa_instruction, instruction->inst.data(), *isa_size);
*isa_memory_size = instruction->size;
return ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS;
}
rocprofiler_thread_trace_decoder_status_t
trace_callback(rocprofiler_thread_trace_decoder_record_type_t record_type_id,
void* trace_events,
uint64_t trace_size,
void* userdata)
{
ROCP_FATAL_IF(userdata == nullptr) << "Userdata is null!";
auto* trace_data = static_cast<trace_data_t*>(userdata);
trace_data->cb(record_type_id, trace_events, trace_size, trace_data->userdata);
return ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS;
}
} // namespace
extern "C" {
rocprofiler_status_t
rocprofiler_trace_decode(rocprofiler_thread_trace_decoder_handle_t handle,
rocprofiler_thread_trace_decoder_callback_t user_callback,
void* data,
uint64_t size,
void* userdata)
{
auto decoder = get_dl(handle);
if(decoder == nullptr) return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
trace_data_t cbdata{.data = static_cast<uint8_t*>(data),
.size = size,
.decoder = decoder,
.cb = user_callback,
.userdata = userdata};
auto status =
decoder->dl->att_parse_data_fn(copy_trace_data, trace_callback, isa_callback, &cbdata);
if(status != ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS)
{
const char* statustr = decoder->dl->att_status_fn(status);
if(statustr == nullptr) statustr = "Unknown error";
ROCP_ERROR << "Callback failed with status " << status << ": " << statustr;
}
return ROCPROFILER_STATUS_SUCCESS;
}
const char*
rocprofiler_thread_trace_decoder_info_string(rocprofiler_thread_trace_decoder_handle_t handle,
rocprofiler_thread_trace_decoder_info_t info)
{
auto decoder = get_dl(handle);
if(decoder == nullptr) return nullptr;
return decoder->dl->att_info_fn(info);
}
}
@@ -0,0 +1,56 @@
// MIT License
//
// Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// 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/thread_trace/dl.hpp"
#include "lib/common/filesystem.hpp"
#include <dlfcn.h>
#include <cassert>
#include <cstdlib>
namespace rocprofiler
{
namespace thread_trace
{
DL::DL(const char* libpath)
{
if(libpath == nullptr) return;
auto path = common::filesystem::path(libpath) / "librocprof-trace-decoder.so";
handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if(!handle) return;
att_parse_data_fn =
reinterpret_cast<ParseFn*>(dlsym(handle, "rocprof_trace_decoder_parse_data"));
att_info_fn = reinterpret_cast<InfoFn*>(dlsym(handle, "rocprof_trace_decoder_get_info_string"));
att_status_fn =
reinterpret_cast<StatusFn*>(dlsym(handle, "rocprof_trace_decoder_get_status_string"));
};
DL::~DL()
{
if(handle) dlclose(handle);
}
} // namespace thread_trace
} // namespace rocprofiler
@@ -0,0 +1,58 @@
// MIT License
//
// Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
#pragma once
#include "lib/rocprofiler-sdk/thread_trace/trace_decoder_api.h"
#include <memory>
namespace rocprofiler
{
namespace thread_trace
{
class DL
{
using ParseFn = decltype(rocprof_trace_decoder_parse_data);
using InfoFn = decltype(rocprof_trace_decoder_get_info_string);
using StatusFn = decltype(rocprof_trace_decoder_get_status_string);
public:
DL(const char* libpath);
~DL();
DL(DL&) = delete;
DL(DL&& other) = delete;
bool valid() const
{
return handle != nullptr && att_parse_data_fn != nullptr && att_info_fn != nullptr &&
att_status_fn != nullptr;
};
ParseFn* att_parse_data_fn = nullptr;
InfoFn* att_info_fn = nullptr;
StatusFn* att_status_fn = nullptr;
void* handle = nullptr;
};
} // namespace thread_trace
} // namespace rocprofiler
@@ -37,13 +37,13 @@ using DeviceThreadTracer = rocprofiler::thread_trace::DeviceThreadTracer;
extern "C" {
rocprofiler_status_t
rocprofiler_configure_dispatch_thread_trace_service(
rocprofiler_context_id_t context_id,
rocprofiler_agent_id_t agent_id,
rocprofiler_att_parameter_t* parameters,
size_t num_parameters,
rocprofiler_att_dispatch_callback_t dispatch_callback,
rocprofiler_att_shader_data_callback_t shader_callback,
void* callback_userdata)
rocprofiler_context_id_t context_id,
rocprofiler_agent_id_t agent_id,
rocprofiler_thread_trace_parameter_t* parameters,
size_t num_parameters,
rocprofiler_thread_trace_dispatch_callback_t dispatch_callback,
rocprofiler_thread_trace_shader_data_callback_t shader_callback,
void* callback_userdata)
{
ROCP_TRACE << "Configuring Dispatch ATT for agent " << agent_id.handle;
@@ -69,30 +69,37 @@ rocprofiler_configure_dispatch_thread_trace_service(
auto id_map = rocprofiler::counters::getPerfCountersIdMap();
for(size_t p = 0; p < num_parameters; p++)
{
const rocprofiler_att_parameter_t& param = parameters[p];
if(param.type > ROCPROFILER_ATT_PARAMETER_LAST)
const rocprofiler_thread_trace_parameter_t& param = parameters[p];
if(param.type > ROCPROFILER_THREAD_TRACE_PARAMETER_LAST)
return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
switch(param.type)
{
case ROCPROFILER_ATT_PARAMETER_TARGET_CU: pack.target_cu = param.value; break;
case ROCPROFILER_ATT_PARAMETER_SHADER_ENGINE_MASK:
case ROCPROFILER_THREAD_TRACE_PARAMETER_TARGET_CU: pack.target_cu = param.value; break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_SHADER_ENGINE_MASK:
pack.shader_engine_mask = param.value;
break;
case ROCPROFILER_ATT_PARAMETER_BUFFER_SIZE: pack.buffer_size = param.value; break;
case ROCPROFILER_ATT_PARAMETER_SIMD_SELECT: pack.simd_select = param.value; break;
case ROCPROFILER_ATT_PARAMETER_PERFCOUNTER:
case ROCPROFILER_THREAD_TRACE_PARAMETER_BUFFER_SIZE:
pack.buffer_size = param.value;
break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_SIMD_SELECT:
pack.simd_select = param.value;
break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTER:
{
auto event_it = id_map.find(param.counter_id.handle);
if(event_it != id_map.end())
pack.perfcounters.push_back({event_it->second, param.simd_mask});
}
break;
case ROCPROFILER_ATT_PARAMETER_PERFCOUNTERS_CTRL:
case ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTERS_CTRL:
pack.perfcounter_ctrl = param.value;
break;
case ROCPROFILER_ATT_PARAMETER_SERIALIZE_ALL: pack.bSerialize = param.value != 0; break;
case ROCPROFILER_ATT_PARAMETER_LAST: return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
case ROCPROFILER_THREAD_TRACE_PARAMETER_SERIALIZE_ALL:
pack.bSerialize = param.value != 0;
break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_LAST:
return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
}
}
@@ -104,12 +111,12 @@ rocprofiler_configure_dispatch_thread_trace_service(
rocprofiler_status_t
rocprofiler_configure_device_thread_trace_service(
rocprofiler_context_id_t context_id,
rocprofiler_agent_id_t agent_id,
rocprofiler_att_parameter_t* parameters,
size_t num_parameters,
rocprofiler_att_shader_data_callback_t shader_callback,
rocprofiler_user_data_t userdata)
rocprofiler_context_id_t context_id,
rocprofiler_agent_id_t agent_id,
rocprofiler_thread_trace_parameter_t* parameters,
size_t num_parameters,
rocprofiler_thread_trace_shader_data_callback_t shader_callback,
rocprofiler_user_data_t userdata)
{
ROCP_TRACE << "Configuring Device ATT for agent " << agent_id.handle;
@@ -131,32 +138,37 @@ rocprofiler_configure_device_thread_trace_service(
auto id_map = rocprofiler::counters::getPerfCountersIdMap();
for(size_t p = 0; p < num_parameters; p++)
{
const rocprofiler_att_parameter_t& param = parameters[p];
if(param.type > ROCPROFILER_ATT_PARAMETER_LAST)
const rocprofiler_thread_trace_parameter_t& param = parameters[p];
if(param.type > ROCPROFILER_THREAD_TRACE_PARAMETER_LAST)
return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
switch(param.type)
{
case ROCPROFILER_ATT_PARAMETER_TARGET_CU: pack.target_cu = param.value; break;
case ROCPROFILER_ATT_PARAMETER_SHADER_ENGINE_MASK:
case ROCPROFILER_THREAD_TRACE_PARAMETER_TARGET_CU: pack.target_cu = param.value; break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_SHADER_ENGINE_MASK:
pack.shader_engine_mask = param.value;
break;
case ROCPROFILER_ATT_PARAMETER_BUFFER_SIZE: pack.buffer_size = param.value; break;
case ROCPROFILER_ATT_PARAMETER_SIMD_SELECT: pack.simd_select = param.value; break;
case ROCPROFILER_ATT_PARAMETER_PERFCOUNTER:
case ROCPROFILER_THREAD_TRACE_PARAMETER_BUFFER_SIZE:
pack.buffer_size = param.value;
break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_SIMD_SELECT:
pack.simd_select = param.value;
break;
case ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTER:
{
auto event_it = id_map.find(param.counter_id.handle);
if(event_it != id_map.end())
pack.perfcounters.push_back({event_it->second, param.simd_mask});
}
break;
case ROCPROFILER_ATT_PARAMETER_PERFCOUNTERS_CTRL:
case ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTERS_CTRL:
pack.perfcounter_ctrl = param.value;
break;
case ROCPROFILER_ATT_PARAMETER_SERIALIZE_ALL:
case ROCPROFILER_THREAD_TRACE_PARAMETER_SERIALIZE_ALL:
if(param.value != 0) return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
break;
case ROCPROFILER_ATT_PARAMETER_LAST: return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
case ROCPROFILER_THREAD_TRACE_PARAMETER_LAST:
return ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT;
}
}
@@ -31,7 +31,7 @@
#include "lib/rocprofiler-sdk/hsa/queue.hpp"
#include "lib/rocprofiler-sdk/hsa/queue_controller.hpp"
#include "lib/rocprofiler-sdk/registration.hpp"
#include "lib/rocprofiler-sdk/thread_trace/att_core.hpp"
#include "lib/rocprofiler-sdk/thread_trace/core.hpp"
#include <glog/logging.h>
#include <gtest/gtest.h>
@@ -134,11 +134,11 @@ TEST(thread_trace, configure_test)
rocprofiler_context_id_t ctx{0};
ROCPROFILER_CALL(rocprofiler_create_context(&ctx), "context creation failed");
std::vector<rocprofiler_att_parameter_t> params;
params.push_back({ROCPROFILER_ATT_PARAMETER_TARGET_CU, {1}});
params.push_back({ROCPROFILER_ATT_PARAMETER_SHADER_ENGINE_MASK, {0xF}});
params.push_back({ROCPROFILER_ATT_PARAMETER_BUFFER_SIZE, {0x1000000}});
params.push_back({ROCPROFILER_ATT_PARAMETER_SIMD_SELECT, {0xF}});
std::vector<rocprofiler_thread_trace_parameter_t> params;
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_TARGET_CU, {1}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_SHADER_ENGINE_MASK, {0xF}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_BUFFER_SIZE, {0x1000000}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_SIMD_SELECT, {0xF}});
auto agents = hsa::get_queue_controller()->get_supported_agents();
ASSERT_GT(agents.size(), 0);
@@ -156,7 +156,7 @@ TEST(thread_trace, configure_test)
rocprofiler_kernel_id_t,
rocprofiler_dispatch_id_t,
void*,
rocprofiler_user_data_t*) { return ROCPROFILER_ATT_CONTROL_NONE; },
rocprofiler_user_data_t*) { return ROCPROFILER_THREAD_TRACE_CONTROL_NONE; },
[](rocprofiler_agent_id_t, int64_t, void*, size_t, rocprofiler_user_data_t) {},
nullptr);
}
@@ -180,17 +180,17 @@ TEST(thread_trace, perfcounters_configure_test)
// Only GFX9 SQ Block counters are supported
std::vector<std::pair<std::string, uint64_t>> perf_counters = {
{"SQ_WAVES", 0x1}, {"SQ_WAVES", 0x2}, {"SQ_WAVES", 0x2}, {"GRBM_COUNT", 0x3}};
std::set<std::pair<uint32_t, uint32_t>> expected;
std::vector<rocprofiler_att_parameter_t> params;
params.push_back({ROCPROFILER_ATT_PARAMETER_PERFCOUNTERS_CTRL, {1}});
std::set<std::pair<uint32_t, uint32_t>> expected;
std::vector<rocprofiler_thread_trace_parameter_t> params;
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTERS_CTRL, {1}});
auto metrics = rocprofiler::counters::getMetricsForAgent("gfx90a");
for(auto& [counter_name, simd_mask] : perf_counters)
for(auto& metric : metrics)
if(metric.name() == counter_name)
{
rocprofiler_att_parameter_t att_param;
att_param.type = ROCPROFILER_ATT_PARAMETER_PERFCOUNTER;
rocprofiler_thread_trace_parameter_t att_param;
att_param.type = ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTER;
att_param.counter_id = rocprofiler_counter_id_t{.handle = metric.id()};
att_param.simd_mask = simd_mask;
params.push_back(att_param);
@@ -213,7 +213,7 @@ TEST(thread_trace, perfcounters_configure_test)
rocprofiler_kernel_id_t,
rocprofiler_dispatch_id_t,
void*,
rocprofiler_user_data_t*) { return ROCPROFILER_ATT_CONTROL_NONE; },
rocprofiler_user_data_t*) { return ROCPROFILER_THREAD_TRACE_CONTROL_NONE; },
[](rocprofiler_agent_id_t, int64_t, void*, size_t, rocprofiler_user_data_t) {},
nullptr);
}
@@ -273,18 +273,18 @@ query_available_agents(rocprofiler_agent_version_t /* version */,
const auto* agent = static_cast<const rocprofiler_agent_v0_t*>(agents[idx]);
if(agent->type != ROCPROFILER_AGENT_TYPE_GPU) continue;
std::vector<rocprofiler_att_parameter_t> params;
params.push_back({ROCPROFILER_ATT_PARAMETER_TARGET_CU, {1}});
params.push_back({ROCPROFILER_ATT_PARAMETER_SHADER_ENGINE_MASK, {0xF}});
params.push_back({ROCPROFILER_ATT_PARAMETER_BUFFER_SIZE, {0x1000000}});
params.push_back({ROCPROFILER_ATT_PARAMETER_SIMD_SELECT, {0xF}});
params.push_back({ROCPROFILER_ATT_PARAMETER_PERFCOUNTERS_CTRL, {1}});
std::vector<rocprofiler_thread_trace_parameter_t> params;
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_TARGET_CU, {1}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_SHADER_ENGINE_MASK, {0xF}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_BUFFER_SIZE, {0x1000000}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_SIMD_SELECT, {0xF}});
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTERS_CTRL, {1}});
{
auto metrics = rocprofiler::counters::getMetricsForAgent("gfx90a");
rocprofiler_att_parameter_t att_param;
att_param.type = ROCPROFILER_ATT_PARAMETER_PERFCOUNTER;
rocprofiler_thread_trace_parameter_t att_param;
att_param.type = ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTER;
att_param.simd_mask = 0xF;
for(auto& metric : metrics)
if(metric.name() == "SQ_WAVES") rocprofiler_counter_id_t{.handle = metric.id()};
@@ -0,0 +1,131 @@
// MIT License
//
// Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
#pragma once
#include <rocprofiler-sdk/experimental/thread-trace/trace_decoder_types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS = 0,
ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR,
ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES,
ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_ARGUMENT,
ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_SHADER_DATA,
ROCPROFILER_THREAD_TRACE_DECODER_STATUS_LAST
} rocprofiler_thread_trace_decoder_status_t;
/**
* @brief Callback for rocprofiler to return traces back to rocprofiler.
* @param[in] trace_type_id One of rocprofiler_thread_trace_decoder_record_type_t
* @param[in] trace_events A pointer to sequence of events, of size trace_size.
* @param[in] trace_size The number of events in the trace.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
*/
typedef rocprofiler_thread_trace_decoder_status_t (*rocprof_trace_decoder_trace_callback_t)(
rocprofiler_thread_trace_decoder_record_type_t record_type_id,
void* trace_events,
uint64_t trace_size,
void* userdata);
/**
* @brief Callback for rocprofiler to return ISA to decoder.
* The caller must copy a desired instruction on isa_instruction and source_reference,
* while obeying the max length passed by the caller.
* If the caller's length is insufficient, then this function writes the minimum sizes to isa_size
* and source_size and returns ::ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES.
* If call returns _SUCCESS, isa_size and source_size must be written with bytes used.
* @param[out] instruction Where to copy the ISA line to.
* @param[out] memory_size (Auto) The number of bytes to next instruction. 0 for custom ISA.
* @param[inout] size Size of returned ISA string.
* @param[in] address The code object ID and offset from base vaddr.
* If marker_id == 0, this parameter is raw virtual address with no codeobj ID information.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
* @retval ::ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS on success.
* @retval ::ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR on generic error.
* @retval ::ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_ARGUMENT for invalid address.
* @retval ::ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES for insufficient
* isa_size.
*/
typedef rocprofiler_thread_trace_decoder_status_t (*rocprof_trace_decoder_isa_callback_t)(
char* instruction,
uint64_t* memory_size,
uint64_t* size,
rocprofiler_thread_trace_decoder_pc_t address,
void* userdata);
/**
* @brief Callback for the decoder to retrieve Shader Engine data. Return zero to end parsing.
* @param[out] buffer The buffer to fill up with SE data.
* @param[out] buffer_size The space available in the buffer.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
* @returns Number of bytes remaining.
* @retval 0 if no more SE data is available. Parsing will stop.
* @retval buffer_size if the buffer does not hold enough data.
* @retval 0 > ret > buffer_size for partially filled buffer, and call ends.
*/
typedef uint64_t (*rocprof_trace_decoder_se_data_callback_t)(uint8_t** buffer,
uint64_t* buffer_size,
void* userdata);
/**
* @brief Parses thread trace data.
* @param[in] se_data_callback Callback to return shader engine data from.
* @param[in] trace_callback Callback where the trace data is returned to.
* @param[in] isa_callback Callback to return ISA lines.
* @param[in] userdata Userdata passed back to caller via callback.
*/
rocprofiler_thread_trace_decoder_status_t
rocprof_trace_decoder_parse_data(rocprof_trace_decoder_se_data_callback_t se_data_callback,
rocprof_trace_decoder_trace_callback_t trace_callback,
rocprof_trace_decoder_isa_callback_t isa_callback,
void* userdata);
/**
* @brief Returns the description of a rocprofiler_thread_trace_decoder_info_t record.
* @param[in] info The decoder info received
* @retval null terminated string as description of "info".
*/
const char*
rocprof_trace_decoder_get_info_string(rocprofiler_thread_trace_decoder_info_t info);
const char*
rocprof_trace_decoder_get_status_string(rocprofiler_thread_trace_decoder_status_t status);
typedef void (*rocprofiler_thread_trace_decoder_debug_callback_t)(int64_t time,
const char* type,
const char* info,
void* userdata);
rocprofiler_thread_trace_decoder_status_t
rocprof_trace_decoder_dump_data(const char* data,
size_t data_size,
rocprofiler_thread_trace_decoder_debug_callback_t cb,
void* userdata);
#ifdef __cplusplus
}
#endif