AQLprofile SQTT double buffer support (#1787)

Этот коммит содержится в:
Giovanni Lenzi Baraldi
2025-11-11 13:01:22 +01:00
коммит произвёл GitHub
родитель cf536a8c1a
Коммит 07a563c475
10 изменённых файлов: 551 добавлений и 144 удалений
+111 -59
Просмотреть файл
@@ -29,6 +29,7 @@
#include <unordered_map>
#include "pm4/cmd_config.h"
#include "trace_decoder_instrument.h"
#define SQTT_PERFCOUNTER_TOKEN (1u << 14)
#define SQTT_PERFCOUNTER_SIMD_MASK 24
@@ -37,36 +38,6 @@ namespace pm4_builder {
class CmdBuffer;
class CmdBuilder;
enum ATT_OPCODES {
ATT_CODEOBJ_OPCODE = 4,
ATT_TIMESTAMP_OPCODE,
ATT_AGENT_INFO_OPCODE,
};
enum ATT_AGENT_INFO_TYPE {
ATT_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ = 0,
ATT_AGENT_INFO_TYPE_COUNTER_FREQUENCY,
};
union att_decoder_packet_header_t {
struct {
unsigned int opcode : 8;
unsigned int type : 4;
unsigned int data20 : 20;
};
unsigned int u32All;
};
union att_decoder_rocm_header_t {
struct {
unsigned int char1 : 8; //!< '\0'
unsigned int char2 : 8; //!< 'R'
unsigned int char3 : 8; //!< 'O'
unsigned int char4 : 8; //!< 'C'
};
unsigned int u32All;
};
/* Class responsible for locking PM4 packets to a specific XCC (mask).
Starts locking future packets on constructor.
Stops locking when the destructor is called.
@@ -116,9 +87,10 @@ struct TraceControl
uint32_t status{0};
uint32_t cntr{0};
uint32_t wptr{0};
uint32_t _reserved{0};
uint32_t status2{0};
uint64_t gpu_clock_cnt_start{0};
uint64_t gpu_clock_cnt_end{0};
uint32_t status_double_buffer{0};
};
// Encapsulates the various Api and structures that are used to enable
@@ -139,6 +111,10 @@ class SqttBuilder {
// Builds Pm4 command stream to program hardware registers that
// inserts "data" into the SQTT buffer as USERDATA_2 (data_lo) and USERDATA_3 (data_hi)
virtual hsa_status_t InsertCodeobjMarker(CmdBuffer* cmd_buffer, uint32_t data, unsigned channel) = 0;
// Builds PM4 command stream to swap SQTT buffer to the next
virtual void Swapbuffer(CmdBuffer* cmd_buffer, TraceConfig* config, void* addr, void* prev, int se_id, bool buf1) = 0;
// Builds PM4 command stream to query status bit
virtual void GetStatusPacket(CmdBuffer* cmd_buffer, TraceConfig* config, TraceControl& control, int se_id) = 0;
virtual void InsertTimestampMarker(CmdBuffer* cmd_buffer, uint64_t* addr) {};
@@ -146,6 +122,8 @@ class SqttBuilder {
virtual size_t GetUTCErrorMask() const = 0;
// Returns TT_CONTROL_FULL_MASK
virtual size_t GetBufferFullMask() const = 0;
// Returns TT_LOCKDOWN_FAIL for double buffering
virtual size_t GetLockDownFailMask() const = 0;
// Returns TT_WRITE_PTR_MASK
virtual size_t GetWritePtrMask() const = 0;
// Returns size of block in bytes per increment in WPTR
@@ -176,6 +154,7 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
virtual size_t GetUTCErrorMask() const override { return Primitives::TT_CONTROL_UTC_ERR_MASK; };
// Returns TT_CONTROL_FULL_MASK
virtual size_t GetBufferFullMask() const override { return Primitives::TT_CONTROL_FULL_MASK; };
virtual size_t GetLockDownFailMask() const override { return Primitives::TT_LOCKDOWN_FAIL; };
// Returns TT_WRITE_PTR_MASK
virtual size_t GetWritePtrMask() const override { return Primitives::TT_WRITE_PTR_MASK; };
// Returns size of block in bytes per increment in WPTR
@@ -237,7 +216,10 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
// to 4KB per thread trace specification
const uint64_t se_number_xcc = se_number_total / GetXCCNumber();
uint64_t base_addr = reinterpret_cast<uint64_t>(config->data_buffer_ptr);
const uint64_t base_step = GetBaseStep(config->data_buffer_size, config->se_mask);
if (Primitives::GFXIP_LEVEL == 10 || Primitives::GFXIP_LEVEL == 11)
config->capacity_per_disabled_se = 1 << Primitives::TT_BUFF_ALIGN_SHIFT;
const uint64_t base_step = GetBaseStep(config);
// Old v1 API calls this with buffer == 0 first
if (config->data_buffer_size > 0)
@@ -248,10 +230,7 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
else if (base_step < (1ul<<17))
throw std::runtime_error("SQTT Buffer size too low");
}
config->capacity_per_se = base_step;
config->capacity_per_disabled_se = 1 << Primitives::TT_BUFF_ALIGN_SHIFT;
const bool legacy_mode =
config->deprecated_mask && config->deprecated_tokenMask && config->deprecated_tokenMask2;
@@ -334,12 +313,24 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
Primitives::sqtt_buffer_size_value(base_step, 0));
// Program the thread trace ctrl register
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_CTRL_ADDR,
Primitives::sqtt_ctrl_value(true));
Primitives::sqtt_ctrl_value(true, false));
// Issue a CSPartialFlush cmd including cache flush
if (config->concurrent == 0) builder.BuildWriteWaitIdlePacket(cmd_buffer);
builder.BuildWriteWaitIdlePacket(cmd_buffer);
// Program the thread trace mode register, mode ON
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_MODE_ADDR,
Primitives::sqtt_mode_on_value());
Primitives::sqtt_mode_on_value(!config->buffer_data.empty()));
// If we are in double buffer mode
if (!config->buffer_data.empty())
{
builder.BuildWriteWaitIdlePacket(cmd_buffer);
uint64_t buf2_addr = reinterpret_cast<uint64_t>(config->buffer_data.at(se_index).at(0));
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BASE_ADDR,
Primitives::sqtt_base_value_lo(buf2_addr));
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BASE2_ADDR,
Primitives::sqtt_base_value_hi(buf2_addr));
}
base_addr += base_step;
}
// Reset the GRBM to broadcast mode
@@ -360,7 +351,9 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
const unsigned baddr_lo = Low32(base_addr >> Primitives::TT_BUFF_ALIGN_SHIFT);
const unsigned baddr_hi = High32(base_addr >> Primitives::TT_BUFF_ALIGN_SHIFT);
const uint64_t sqtt_size = bMaskedIn ? base_step : config->capacity_per_disabled_se;
const uint32_t ctrl_val = Primitives::sqtt_ctrl_value(true);
if (sqtt_size == 0) continue;
uint32_t ctrl_val = Primitives::sqtt_ctrl_value(true, !config->buffer_data.empty());
Select_GRBM_SE_SH0(cmd_buffer, index);
builder.BuildPrimeL2(cmd_buffer, base_addr);
@@ -395,7 +388,20 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
WriteConfigPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_TOKEN_MASK_ADDR, token_mask);
// Program the thread trace ctrl register
WriteConfigPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_CTRL_ADDR, ctrl_val);
// If we are in double buffer mode
if (!config->buffer_data.empty())
{
if (Primitives::GFXIP_LEVEL != 12) throw std::runtime_error("Not supported");
uint64_t buf1_addr = reinterpret_cast<uint64_t>(config->buffer_data.at(index).at(0));
unsigned buff1_lo = Low32(buf1_addr >> Primitives::TT_BUFF_ALIGN_SHIFT);
unsigned buff1_hi = High32(buf1_addr >> Primitives::TT_BUFF_ALIGN_SHIFT);
WriteConfigPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BUF1_SIZE_ADDR, Primitives::sqtt_buffer0_size_value(sqtt_size));
WriteConfigPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BUF1_BASE_LO_ADDR, buff1_lo);
builder.BuildWriteWaitIdlePacket(cmd_buffer);
WriteConfigPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BUF1_BASE_HI_ADDR, buff1_hi);
}
base_addr += sqtt_size;
}
for (uint64_t index = 0; index < se_number_total; index++) {
@@ -408,7 +414,7 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
}
builder.BuildWriteWaitIdlePacket(cmd_buffer);
att_decoder_rocm_header_t header{};
rocprof_trace_decoder_instrument_enable_t header{};
header.char1 = '\0';
header.char2 = 'R';
header.char3 = 'O';
@@ -418,18 +424,18 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, header.u32All);
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, 524801);
att_decoder_packet_header_t packet{};
packet.opcode = ATT_AGENT_INFO_OPCODE;
rocprof_trace_decoder_packet_header_t packet{};
packet.opcode = ROCPROF_TRACE_DECODER_PACKET_OPCODE_AGENT_INFO;
if (config->enable_rt_timestamp)
{
packet.type = ATT_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ;
packet.type = ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ;
packet.data20 = this->timestamp_freq / 1000;
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, packet.u32All);
}
if (Primitives::GFXIP_LEVEL == 9 && config->perfcounters.size())
{
packet.type = ATT_AGENT_INFO_TYPE_COUNTER_FREQUENCY;
packet.type = ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_COUNTER_INTERVAL;
packet.data20 = (1 + cu_per_se) * ((config->perfcounters.size() + 3) & ~3) * config->perfPeriod;
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, packet.u32All);
}
@@ -505,14 +511,12 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
// Initialize cache flush request object
builder.BuildCacheFlushPacket(cmd_buffer, size_t(config->control_buffer_ptr),
config->control_buffer_size);
builder.BuildCacheFlushPacket(cmd_buffer, size_t(config->data_buffer_ptr),
config->data_buffer_size);
// Program zero size of thread trace buffer
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_SIZE_ADDR,
Primitives::sqtt_zero_size_value());
// Program the thread trace ctrl register
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_CTRL_ADDR,
Primitives::sqtt_ctrl_value(true));
Primitives::sqtt_ctrl_value(true, false));
// Issue a CSPartialFlush cmd including cache flush
builder.BuildWriteWaitIdlePacket(cmd_buffer);
} else {
@@ -529,7 +533,7 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
}
// Program the thread trace ctrl register to set mode to 0
const uint32_t ctrl_val = Primitives::sqtt_ctrl_value(false);
const uint32_t ctrl_val = Primitives::sqtt_ctrl_value(false, false);
WriteConfigPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_CTRL_ADDR, ctrl_val);
{
@@ -566,6 +570,10 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
builder.BuildCopyRegDataPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_WPTR_ADDR, &control.wptr,
Primitives::COPY_DATA_SEL_COUNT_1DW_PRM, true);
if (Primitives::GFXIP_LEVEL >= 12)
builder.BuildCopyRegDataPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_STATUS2_ADDR,
&control.status2, Primitives::COPY_DATA_SEL_COUNT_1DW_PRM, true);
}
uint32_t GetXCCNumber() const { return xcc_number_; }
@@ -579,33 +587,33 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
return std::max<uint64_t>(num_enabled, 1u);
}
uint64_t GetBaseStep(uint64_t buffersize, uint64_t se_mask) const {
// Get selected
uint64_t num_enabled = PopCount(se_mask);
int64_t num_disabled = (64 - num_enabled) << 12;
uint64_t GetBaseStep(TraceConfig* config) const {
// Get number of selected shader engines
uint64_t num_enabled = PopCount(config->se_mask);
int64_t size_disabled = (64 - num_enabled) * config->capacity_per_disabled_se;
// Make sure num divides buffersize
int64_t buffer_per_se = std::max<int64_t>(0, buffersize - num_disabled) / num_enabled;
int64_t buffer_per_se = (config->data_buffer_size - size_disabled) / num_enabled;
return uint64_t(buffer_per_se) & ~((1 << Primitives::TT_BUFF_ALIGN_SHIFT) - 1);
}
virtual hsa_status_t InsertCodeobjMarker(CmdBuffer* cmd_buffer, uint32_t data,
unsigned channel) override {
att_decoder_packet_header_t header{};
header.opcode = ATT_CODEOBJ_OPCODE;
rocprof_trace_decoder_packet_header_t header{};
header.opcode = ROCPROF_TRACE_DECODER_PACKET_OPCODE_CODEOBJ;
header.type = channel;
header.data20 = 0;
auto userdata_channel = Primitives::SQ_THREAD_TRACE_USERDATA_2;
SetGRBMToBroadcast(cmd_buffer);
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, 4 | (channel << 8));
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, header.u32All);
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, data);
return HSA_STATUS_SUCCESS;
}
virtual void InsertTimestampMarker(CmdBuffer* cmd_buffer, uint64_t* addr) override
{
att_decoder_packet_header_t header{};
header.opcode = ATT_TIMESTAMP_OPCODE;
rocprof_trace_decoder_packet_header_t header{};
header.opcode = ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP;
header.type = 0;
header.data20 = 0;
@@ -621,6 +629,50 @@ class GpuSqttBuilder : public SqttBuilder, protected Primitives {
builder.BuildWritePConfigRegPacket(cmdbuf, reg, value);
}
void GetStatusPacket(CmdBuffer* cmd_buffer, TraceConfig* config, TraceControl& control, int se_id) override
{
int se_per_xcc = se_number_total / GetXCCNumber();
XCC_Packet_Lock<Builder> lock(builder, cmd_buffer, GetXCCNumber(), se_id / se_per_xcc);
Select_GRBM_SE_SH0(cmd_buffer, se_id % se_per_xcc);
auto status_addr = (Primitives::GFXIP_LEVEL >= 12) ? Primitives::SQ_THREAD_TRACE_STATUS2_ADDR : Primitives::SQ_THREAD_TRACE_STATUS_ADDR;
builder.BuildCopyRegDataPacket(cmd_buffer, status_addr, &control.status_double_buffer, Primitives::COPY_DATA_SEL_COUNT_1DW_PRM, false);
builder.BuildWriteWaitIdlePacket(cmd_buffer);
builder.BuildCacheFlushPacket(cmd_buffer, size_t(&control), sizeof(TraceControl));
SetGRBMToBroadcast(cmd_buffer);
}
void Swapbuffer(CmdBuffer* cmd_buffer, TraceConfig* config, void* addr, void* prev, int se_id, bool buf1) override
{
int se_per_xcc = se_number_total / GetXCCNumber();
uint64_t base_addr = reinterpret_cast<uint64_t>(addr);
XCC_Packet_Lock<Builder> lock(builder, cmd_buffer, GetXCCNumber(), se_id / se_per_xcc);
Select_GRBM_SE_SH0(cmd_buffer, se_id % se_per_xcc);
if (Primitives::GFXIP_LEVEL == 9)
{
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BASE_ADDR, Primitives::sqtt_base_value_lo(base_addr));
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::SQ_THREAD_TRACE_BASE2_ADDR, Primitives::sqtt_base_value_hi(base_addr));
}
else
{
unsigned buff1_lo = Low32(base_addr >> Primitives::TT_BUFF_ALIGN_SHIFT);
unsigned buff1_hi = High32(base_addr >> Primitives::TT_BUFF_ALIGN_SHIFT) & 0x3FFFu;
auto reg_lo = buf1 ? Primitives::SQ_THREAD_TRACE_BUF1_BASE_LO_ADDR : Primitives::SQ_THREAD_TRACE_BUF0_BASE_LO_ADDR;
auto reg_hi = buf1 ? Primitives::SQ_THREAD_TRACE_BUF1_BASE_HI_ADDR : Primitives::SQ_THREAD_TRACE_BUF0_BASE_HI_ADDR;
WriteConfigPacket(cmd_buffer, reg_lo, buff1_lo);
builder.BuildWriteWaitIdlePacket(cmd_buffer);
WriteConfigPacket(cmd_buffer, reg_hi, buff1_hi);
}
builder.BuildCacheFlushPacket(cmd_buffer, size_t(prev), config->data_buffer_size);
SetGRBMToBroadcast(cmd_buffer);
}
size_t se_number_total{};
size_t xcc_number_{};
uint32_t timestamp_freq{};
+4 -1
Просмотреть файл
@@ -62,8 +62,11 @@ struct TraceConfig {
// SE mask for tracing; note -> replicated for all XCCs
uint64_t se_mask = 0x11;
// Maps shader engine IDs to list of buffers
std::unordered_map<int, std::vector<void*>> buffer_data{};
uint64_t capacity_per_se = 0x1000;
uint64_t capacity_per_disabled_se = 0x1000;
uint64_t capacity_per_disabled_se = 0;
std::unordered_map<int, int> target_cu_per_se{};
std::unordered_map<int, uint64_t> se_base_addresses{};
+146
Просмотреть файл
@@ -0,0 +1,146 @@
// 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 <stddef.h>
#include <stdint.h>
/**
* This file describes the instrumentation format for rocprof trace decoder 0.1.5.
* Instrumentation is optional for decoding, with the exception of rocprof_trace_decoder_gfx9_header_t.
* Unless specified, all instrumentation packets are written to the USERDATA2 register.
* This is an experimental feature, and as such the instrumentation may be changed without notice.
*
* It is recommended to use code object instrumentation for long traces, to avoid overlapping address spaces
* if code objects are loaded/unloaded during the trace.
* When an ID is found, callbacks involving _trace_decoder_pc_t will return {id, vaddr} instead of {0, memory_address}.
*/
/**
* @brief For gfx9, must be first 8 bytes of the trace binary buffer. Not added in gfx10+.
*/
typedef union rocprof_trace_decoder_gfx9_header_t
{
struct {
uint64_t legacy_version : 13; ///< Must be 0x0 or 0x11
uint64_t gfx9_version2 : 3; ///< 4: MI200 or earlier - 5: MI300 - 6: MI350
uint64_t DSIMDM : 4; ///< Bitmask of SIMDs active
uint64_t DCU : 5; ///< Target CU
uint64_t DSA : 1; ///< Must be zero
uint64_t SEID : 6; ///< Optional: Shader engine ID
uint64_t double_buffer : 1; ///< Double buffering mode enabled
uint64_t reserved2 : 31;
};
uint64_t raw;
} rocprof_trace_decoder_gfx9_header_t;
/**
* @brief Must be first packet on userdata2. Activates instrumentation.
* The 4 characters must be defined as ASCII '\0ROC'. Instrumentation ignored otherwise.
* Optionally, a subsequent write can be sent with version number 524801
*/
typedef union rocprof_trace_decoder_instrument_enable_t
{
struct {
unsigned int char1 : 8; ///< '\0'
unsigned int char2 : 8; ///< 'R'
unsigned int char3 : 8; ///< 'O'
unsigned int char4 : 8; ///< 'C'
};
unsigned int u32All;
} rocprof_trace_decoder_instrument_enable_t;
/**
* @brief Header packet for instrumentation.
* Opcode defines the kind of instrumentation, and type (sometimes) defines a subtype.
* Header packets are expected to be followed by a 32-bit payload on the same register, except where especified.
*/
typedef union rocprof_trace_decoder_packet_header_t
{
struct
{
unsigned int opcode : 8; ///< one of rocprof_trace_decoder_packet_opcode_t
unsigned int type : 4; ///< one of rocprof_trace_decoder_agent_info_type_t or rocprof_trace_decoder_codeobj_marker_type_t
unsigned int data20 : 20; ///< Agent data, if rocprof_trace_decoder_agent_info_type_t.
};
unsigned int u32All;
} rocprof_trace_decoder_packet_header_t;
typedef enum rocprof_trace_decoder_packet_opcode_t
{
ROCPROF_TRACE_DECODER_PACKET_OPCODE_CODEOBJ = 4,
ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP,
ROCPROF_TRACE_DECODER_PACKET_OPCODE_AGENT_INFO ///< Agent info, passed in data20. No payload.
/// @var ROCPROF_TRACE_DECODER_PACKET_OPCODE_CODEOBJ
/// @brief Followed by several rocprof_trace_decoder_codeobj_marker_t
/// Once relevant data is sent, finalize with rocprof_trace_decoder_codeobj_marker_tail_t
/// @var ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP
/// @brief Realtime timestamp to correlate the trace with outside information.
/// Notes: userdata--3--. Gfx9 only. Not necessary for gfx10+.
/// Instead of a single payload, must be followed by 3x USERDATA3 writes, in order:
/// 1) Timestamp low 64bits
/// 2) Timestamp high 64bits
/// 3) Instant sync timestamp, low 32 bits.
} rocprof_trace_decoder_packet_opcode_t;
typedef enum rocprof_trace_decoder_agent_info_type_t
{
ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ = 0, ///< Realtime TS frequency in Khz
ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_COUNTER_INTERVAL, ///< (gfx9) SQTT counter interval in cycles
ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_LAST
} rocprof_trace_decoder_agent_info_type_t;
/**
* @brief Applies code object instrumentation. Sent as the last code object instrumentation packet.
* Instead of _ID_LO and _ID_HI, the legacy_id field can be used for setting the ID.
* IDs can be any (nonzero) user defined number, and will be used in callbacks involving _trace_decoder_pc_t.
* The combination {id, offset} instead of {0, memory_address} is used to avoid overlapping
* addresses when code objects are loaded/unloaded during the trace.
*/
typedef union rocprof_trace_decoder_codeobj_marker_tail_t
{
struct {
uint32_t isUnload : 1; // 0 if code object is being loaded, 1 for unload
uint32_t bFromStart : 1; // Has this code object been loaded before thread trace started?
uint32_t legacy_id : 30; // Nonzero: Code object ID, if it fits in 30 bits.
};
uint32_t raw;
} rocprof_trace_decoder_codeobj_marker_tail_t;
/**
* @brief Defines the type of code object marker. Followed by 32-bit payload.
* Send ADDR/SIZE with _LO/_HI combinations, followed by _TAIL to apply the instrumentation.
*/
typedef enum rocprof_trace_decoder_codeobj_marker_type_t
{
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_TAIL = 0, ///< Payload is a rocprof_trace_decoder_codeobj_marker_tail_t
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_LO,
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_LO,
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_HI,
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_HI,
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_LO,
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_HI,
ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_LAST
} rocprof_trace_decoder_codeobj_marker_type_t;