Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -143,6 +143,19 @@ typedef enum rocprofiler_thread_trace_resource_mode_t
/// @brief Initializes resources at first kernel dispatch per GPU.
} rocprofiler_thread_trace_resource_mode_t;

/**
* @brief GPU and system clock values for a thread trace buffer record.
*
* @p gpu_clock is the timestamp in the GPU clock domain.
* @p system_clock is the same timestamp in the system clock domain.
* Approximate. Both values are zero when the data has no GPU-defined boundary.
*/
typedef struct rocprofiler_thread_trace_timestamp_t
{
uint64_t gpu_clock;
rocprofiler_timestamp_t system_clock;
} rocprofiler_thread_trace_timestamp_t;

/**
* @brief Bundle of shader data delivered to
* rocprofiler_thread_trace_shader_data_callback_t.
Expand All @@ -158,6 +171,11 @@ typedef struct rocprofiler_thread_trace_shader_data_t

rocprofiler_agent_id_t agent; ///< Identifier for the target agent.
rocprofiler_thread_trace_shader_data_flags_t flags; ///< Flags for this data chunk.

/// Timestamp at which collection into this data chunk began.
rocprofiler_thread_trace_timestamp_t start_timestamp;
/// Timestamp at which collection into this data chunk ended.
rocprofiler_thread_trace_timestamp_t end_timestamp;
} rocprofiler_thread_trace_shader_data_t;

/**
Expand Down
20 changes: 20 additions & 0 deletions projects/rocprofiler-sdk/source/lib/aqlprofile/aql_profile_v2.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,12 @@ typedef hsa_status_t (*aqlprofile_pmc_data_callback_t)(aqlprofile_pmc_event_t ev
uint64_t counter_value,
void* userdata);

typedef struct aqlprofile_att_gpu_clock_t
{
uint64_t start; ///< Most recent start-packet clock.
uint64_t latest; ///< Most recent swap- or stop-packet clock.
} aqlprofile_att_gpu_clock_t;

/**
* @brief Data callback for thread trace. This will be called at least once per shader engine
* @param[in] shader Shader Engine ID
Expand Down Expand Up @@ -628,6 +634,20 @@ typedef struct aqlprofile_att_buffer_status_t
uint64_t read_offset;
} aqlprofile_att_buffer_status_t;

/**
* @brief Read GPU clocks written by the ATT start/stop/swap packets.
*
* This query only reads the trace control buffer and does not update buffer status.
*
* @param[out] out Latest GPU clock values.
* @param[in] handle Handle returned by aqlprofile_att_create_packets().
* @param[in] shader_engine_id Shader engine (SE) ID.
*/
hsa_status_t
aqlprofile_att_get_gpu_clock(aqlprofile_att_gpu_clock_t* out,
aqlprofile_handle_t handle,
int shader_engine_id);

/**
* @brief Fn to retrieve buffer status.
* Must be called at least once with has_buffer_swapped=true for every swap packet inserted.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ _internal_aqlprofile_att_create_packets(aqlprofile_handle_t* ha
}

auto* control_ptr = memorymgr->GetTraceControlBuf<pm4_builder::TraceControl>();
// The allocation callback returns uninitialized storage; initialize clocks before GPU writes.
for(size_t i = 0; i < se_number_total; ++i)
{
control_ptr[i].gpu_clock_start = 0;
control_ptr[i].gpu_clock_latest = 0;
}
Comment thread
ApoKalipse-V marked this conversation as resolved.
Resolved

trace_config.control_buffer_ptr = control_ptr;
trace_config.control_buffer_size = control_size;
Expand Down Expand Up @@ -455,6 +461,31 @@ aqlprofile_att_update_buffer_status(aqlprofile_att_buffer_status_t* out,
return HSA_STATUS_SUCCESS;
}

PUBLIC_API hsa_status_t
aqlprofile_att_get_gpu_clock(aqlprofile_att_gpu_clock_t* out,
aqlprofile_handle_t handle,
int shader_engine_id)
{
if(out == nullptr || shader_engine_id < 0) return HSA_STATUS_ERROR_INVALID_ARGUMENT;

auto generic_manager = MemoryManager::GetManager(handle.handle);
auto* manager = dynamic_cast<TraceMemoryManager*>(generic_manager.get());
if(manager == nullptr) return HSA_STATUS_ERROR;

auto* factory = aql_profile::Pm4Factory::Create(manager->AgentHandle());
if(static_cast<uint32_t>(shader_engine_id) >= factory->GetShaderEnginesNumber())
return HSA_STATUS_ERROR_INVALID_ARGUMENT;

const auto se_per_xcc =
factory->GetShaderEnginesNumber() / std::max(1u, factory->GetXccNumber());
volatile auto& control = manager->GetTraceControlBuf<
pm4_builder::TraceControl>()[static_cast<uint32_t>(shader_engine_id) / se_per_xcc];

out->start = control.gpu_clock_start;
out->latest = control.gpu_clock_latest;
return HSA_STATUS_SUCCESS;
}

PUBLIC_API hsa_status_t
aqlprofile_att_get_buffer_packets(uint64_t* header,
hsa_ext_amd_aql_pm4_packet_t* query_status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ class CmdBuilder
/// @param cmdBuf command buffer to be appended with launch command
virtual void BuildPrimeL2(CmdBuffer* cmdBuf, uint64_t addr) = 0;

/// @brief Generates RT packets into thread trace buffer (gfx9 only)
/// @brief Generates an RT timestamp marker in the thread trace buffer (GFX9 only).
/// @param cmdBuf command buffer to be appended with launch command
/// @param dst where gpu clock data is r/w. Must persist during packet dispatch
/// @param reg userdata register address
Expand All @@ -315,6 +315,11 @@ class CmdBuilder
const Register& reg,
uint32_t header){};

/// @brief Copies the GPU clock to memory without writing SQ thread-trace userdata registers.
/// @param cmdBuf command buffer to be appended with the copy command
/// @param dst destination for the GPU clock; must persist during packet dispatch
virtual void BuildReadGPUClockPacket(CmdBuffer* cmdBuf, uint64_t* dst){};

/// @brief Release resources used by CmdBuilder
virtual ~CmdBuilder(){};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,23 @@ class Gfx10CmdBuilder : public CmdBuilder
{
BuildCopyRegDataPacket(cmd, get_addr(reg), dst_addr, size, wait);
}

void BuildReadGPUClockPacket(CmdBuffer* cmd_buffer, uint64_t* dst) override
{
uint32_t header = MakePacket3Header(PACKET3_COPY_DATA, 6 * sizeof(uint32_t));
uint32_t control =
PACKET3_COPY_DATA__SRC_SEL(PACKET3_COPY_DATA__SRC_SEL__GPU_CLOCK_COUNT) |
PACKET3_COPY_DATA__SRC_CACHE_POLICY(PACKET3_COPY_DATA__SRC_CACHE_POLICY__LRU) |
PACKET3_COPY_DATA__DST_SEL(PACKET3_COPY_DATA__DST_SEL__TC_L2) |
PACKET3_COPY_DATA__DST_CACHE_POLICY(PACKET3_COPY_DATA__DST_CACHE_POLICY__LRU) |
PACKET3_COPY_DATA__WR_CONFIRM(PACKET3_COPY_DATA__WR_CONFIRM__WAIT_FOR_CONFIRMATION) |
PACKET3_COPY_DATA__COUNT_SEL(PACKET3_COPY_DATA__COUNT_SEL__64_BITS_OF_DATA);
uint32_t dst_lo = PACKET3_COPY_DATA__DST_64B_ADDR_LO(PtrLow32(dst) >> 3);
uint32_t dst_hi = PACKET3_COPY_DATA__DST_ADDR_HI(PtrHigh32(dst));

uint32_t packet[6] = {header, control, 0, 0, dst_lo, dst_hi};
APPEND_COMMAND_WRAPPER(cmd_buffer, packet);
}
};
} // namespace pm4_builder

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,23 @@ class Gfx11CmdBuilder : public CmdBuilder
{
BuildCopyRegDataPacket(cmd, get_addr(reg), dst_addr, size, wait);
}

void BuildReadGPUClockPacket(CmdBuffer* cmd_buffer, uint64_t* dst) override
{
uint32_t header = MakePacket3Header(PACKET3_COPY_DATA, 6 * sizeof(uint32_t));
uint32_t control =
PACKET3_COPY_DATA__SRC_SEL(PACKET3_COPY_DATA__SRC_SEL__GPU_CLOCK_COUNT) |
PACKET3_COPY_DATA__SRC_CACHE_POLICY(PACKET3_COPY_DATA__SRC_CACHE_POLICY__LRU) |
PACKET3_COPY_DATA__DST_SEL(PACKET3_COPY_DATA__DST_SEL__TC_L2) |
PACKET3_COPY_DATA__DST_CACHE_POLICY(PACKET3_COPY_DATA__DST_CACHE_POLICY__LRU) |
PACKET3_COPY_DATA__WR_CONFIRM(PACKET3_COPY_DATA__WR_CONFIRM__WAIT_FOR_CONFIRMATION) |
PACKET3_COPY_DATA__COUNT_SEL(PACKET3_COPY_DATA__COUNT_SEL__64_BITS_OF_DATA);
uint32_t dst_lo = PACKET3_COPY_DATA__DST_64B_ADDR_LO(PtrLow32(dst) >> 3);
uint32_t dst_hi = PACKET3_COPY_DATA__DST_ADDR_HI(PtrHigh32(dst));

uint32_t packet[6] = {header, control, 0, 0, dst_lo, dst_hi};
APPEND_COMMAND_WRAPPER(cmd_buffer, packet);
}
};

} // namespace pm4_builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,23 @@ class Gfx12CmdBuilder : public CmdBuilder
{
BuildCopyRegDataPacket(cmd, get_addr(reg), dst_addr, size, wait);
}

void BuildReadGPUClockPacket(CmdBuffer* cmd_buffer, uint64_t* dst) override
{
uint32_t header = MakePacket3Header(PACKET3_COPY_DATA, 6 * sizeof(uint32_t));
uint32_t control =
PACKET3_COPY_DATA__SRC_SEL(PACKET3_COPY_DATA__SRC_SEL__GPU_CLOCK_COUNT) |
PACKET3_COPY_DATA__SRC_TEMPORAL(PACKET3_COPY_DATA__SRC_TEMPORAL__LU) |
PACKET3_COPY_DATA__DST_SEL(PACKET3_COPY_DATA__DST_SEL__TC_L2) |
PACKET3_COPY_DATA__DST_TEMPORAL(PACKET3_COPY_DATA__DST_TEMPORAL__LU) |
PACKET3_COPY_DATA__WR_CONFIRM(PACKET3_COPY_DATA__WR_CONFIRM__WAIT_FOR_CONFIRMATION) |
PACKET3_COPY_DATA__COUNT_SEL(PACKET3_COPY_DATA__COUNT_SEL__64_BITS_OF_DATA);
uint32_t dst_lo = PACKET3_COPY_DATA__DST_64B_ADDR_LO(PtrLow32(dst) >> 3);
uint32_t dst_hi = PACKET3_COPY_DATA__DST_ADDR_HI(PtrHigh32(dst));

uint32_t packet[6] = {header, control, 0, 0, dst_lo, dst_hi};
APPEND_COMMAND_WRAPPER(cmd_buffer, packet);
}
};

} // namespace pm4_builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,6 @@ class Gfx9CmdBuilder : public CmdBuilder

std::array<uint32_t, 6> ClockRetrievePacket(uint64_t* dst)
{
auto addr = reinterpret_cast<uint64_t>(dst);

uint32_t header = MakePacket3Header(PACKET3_COPY_DATA, 6 * sizeof(uint32_t));

uint32_t dword2 =
Expand All @@ -560,8 +558,8 @@ class Gfx9CmdBuilder : public CmdBuilder
PACKET3_COPY_DATA__WR_CONFIRM(PACKET3_COPY_DATA__WR_CONFIRM__WAIT_FOR_CONFIRMATION) |
PACKET3_COPY_DATA__COUNT_SEL(PACKET3_COPY_DATA__COUNT_SEL__64_BITS_OF_DATA);

uint32_t dword5 = PACKET3_COPY_DATA__DST_64B_ADDR_LO(addr >> 3);
uint32_t dword6 = PACKET3_COPY_DATA__DST_ADDR_HI(High32(addr));
uint32_t dword5 = PACKET3_COPY_DATA__DST_64B_ADDR_LO(PtrLow32(dst) >> 3);
uint32_t dword6 = PACKET3_COPY_DATA__DST_ADDR_HI(PtrHigh32(dst));

return {header, dword2, 0, 0, dword5, dword6};
}
Expand Down Expand Up @@ -627,6 +625,12 @@ class Gfx9CmdBuilder : public CmdBuilder
APPEND_COMMAND_WRAPPER(cmdBuf, copy_data);
}
}

void BuildReadGPUClockPacket(CmdBuffer* cmdBuf, uint64_t* dst) override
{
auto copy_data = ClockRetrievePacket(dst);
APPEND_COMMAND_WRAPPER(cmdBuf, copy_data);
}
};

} // namespace pm4_builder
Expand Down
62 changes: 41 additions & 21 deletions projects/rocprofiler-sdk/source/lib/aqlprofile/pm4/sqtt_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ struct TraceControl
uint32_t cntr{0};
uint32_t wptr{0};
uint32_t status2{0};
uint64_t gpu_clock_cnt_start{0};
uint64_t gpu_clock_cnt_end{0};
uint64_t gpu_clock_start{0};
uint64_t gpu_clock_latest{0};
uint32_t status_double_buffer{0};
uint32_t wptr_doublebuffer{0};
};
Expand Down Expand Up @@ -524,16 +524,17 @@ class GpuSqttBuilder
(1 + cu_per_se) * ((config->perfcounters.size() + 3) & ~3) * config->perfPeriod;
builder.BuildWriteUConfigRegPacket(cmd_buffer, userdata_channel, packet.u32All);
}
if(Primitives::GFXIP_LEVEL == 9 && config->enable_rt_timestamp)
{
for(size_t xcc = 0; xcc < GetXCCNumber(); xcc++)
{
if(!isXccEnabled(xcc, se_number_xcc, config)) continue;

XCC_Packet_Lock<Builder> lock(builder, cmd_buffer, GetXCCNumber(), xcc);
auto& control = reinterpret_cast<TraceControl*>(config->control_buffer_ptr)[xcc];
InsertTimestampMarker(cmd_buffer, &control.gpu_clock_cnt_start);
CaptureClock(cmd_buffer, &control.gpu_clock_start, config->enable_rt_timestamp);
}
builder.BuildCacheFlushPacket(
cmd_buffer, size_t(config->control_buffer_ptr), config->control_buffer_size);
}
}

Expand All @@ -542,21 +543,19 @@ class GpuSqttBuilder
SetGRBMToBroadcast(cmd_buffer);
const uint32_t se_number_xcc = se_number_total / std::max(1u, GetXCCNumber());

if(Primitives::GFXIP_LEVEL == 9)
{
if(config->enable_rt_timestamp)
for(size_t xcc = 0; xcc < GetXCCNumber(); xcc++)
{
for(size_t xcc = 0; xcc < GetXCCNumber(); xcc++)
{
if(!isXccEnabled(xcc, se_number_xcc, config)) continue;
if(!isXccEnabled(xcc, se_number_xcc, config)) continue;

XCC_Packet_Lock<Builder> lock(builder, cmd_buffer, GetXCCNumber(), xcc);
auto& control =
reinterpret_cast<TraceControl*>(config->control_buffer_ptr)[xcc];
InsertTimestampMarker(cmd_buffer, &control.gpu_clock_cnt_end);
}
XCC_Packet_Lock<Builder> lock(builder, cmd_buffer, GetXCCNumber(), xcc);
auto& control = reinterpret_cast<TraceControl*>(config->control_buffer_ptr)[xcc];
CaptureClock(cmd_buffer, &control.gpu_clock_latest, config->enable_rt_timestamp);
}
}

if(Primitives::GFXIP_LEVEL == 9)
{
// Program the thread trace mode register to disable thread trace
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::SQ_THREAD_TRACE_MODE_ADDR,
Expand Down Expand Up @@ -717,14 +716,30 @@ class GpuSqttBuilder

virtual void InsertTimestampMarker(CmdBuffer* cmd_buffer, uint64_t* addr) override
{
rocprof_trace_decoder_packet_header_t header{};
header.opcode = ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP;
header.type = 0;
header.data20 = 0;
if constexpr(Primitives::GFXIP_LEVEL == 9)
{
rocprof_trace_decoder_packet_header_t header{};
header.opcode = ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP;
header.type = 0;
header.data20 = 0;

SetGRBMToBroadcast(cmd_buffer);
builder.BuildGPUClockPacket(
cmd_buffer, addr, Primitives::SQ_THREAD_TRACE_USERDATA_3, header.u32All);
SetGRBMToBroadcast(cmd_buffer);
builder.BuildGPUClockPacket(
cmd_buffer, addr, Primitives::SQ_THREAD_TRACE_USERDATA_3, header.u32All);
}
}

void CaptureClock(CmdBuffer* cmd_buffer, uint64_t* addr, bool emit_marker)
{
if constexpr(Primitives::GFXIP_LEVEL == 9)
{
if(emit_marker)
{
InsertTimestampMarker(cmd_buffer, addr);
return;
}
}
builder.BuildReadGPUClockPacket(cmd_buffer, addr);
}

template <typename T>
Expand Down Expand Up @@ -803,7 +818,12 @@ class GpuSqttBuilder
WriteConfigPacket(cmd_buffer, reg_lo, buff1_lo);
WriteConfigPacket(cmd_buffer, reg_hi, buff1_hi);
}
auto& control =
reinterpret_cast<TraceControl*>(config->control_buffer_ptr)[se_id / se_per_xcc];
builder.BuildReadGPUClockPacket(cmd_buffer, &control.gpu_clock_latest);
builder.BuildCacheFlushPacket(cmd_buffer, size_t(prev), config->data_buffer_size);
builder.BuildCacheFlushPacket(
cmd_buffer, size_t(config->control_buffer_ptr), config->control_buffer_size);

SetGRBMToBroadcast(cmd_buffer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ forward_cut(agent_state_t& state,
shader_data.read_offset = 0;
shader_data.agent = state.id;
shader_data.flags = ROCPROFILER_THREAD_TRACE_SHADER_DATA_FLAGS_NONE;
shader_data.start_timestamp = original.start_timestamp;
shader_data.end_timestamp = original.end_timestamp;

auto userdata = rocprofiler_user_data_t{};
userdata.value = capture_id.fetch_add(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,21 @@ SQTTBufferingPackets::query_buffer_status()
return query;
}

aqlprofile_att_gpu_clock_t
get_gpu_clock(aqlprofile_handle_t handle, int shader_engine_id)
{
auto clock = aqlprofile_att_gpu_clock_t{};
auto* dl = rocprofiler::thread_trace::get_aqlprofile_dl();
if(dl && dl->get_gpu_clock_fn) dl->get_gpu_clock_fn(&clock, handle, shader_engine_id);
return clock;
}

aqlprofile_att_gpu_clock_t
SQTTBufferingPackets::get_gpu_clock() const
{
return hsa::get_gpu_clock(handle, shader_engine_id);
}

CodeobjMarkerAQLPacket::CodeobjMarkerAQLPacket(const TraceMemoryPool& _tracepool,
uint64_t id,
uint64_t addr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ struct sqtt_buffer_status_t
bool gpu_full{};
};

aqlprofile_att_gpu_clock_t
get_gpu_clock(aqlprofile_handle_t handle, int shader_engine_id);

// Virtual members for mocking in tests
class SQTTBufferingPackets
{
Expand All @@ -293,6 +296,7 @@ class SQTTBufferingPackets

hsa_ext_amd_aql_pm4_packet_t query_status{};
virtual std::optional<sqtt_buffer_status_t> query_buffer_status();
virtual aqlprofile_att_gpu_clock_t get_gpu_clock() const;
virtual hsa_status_t iterate_data(aqlprofile_att_data_callback_t callback, void* data)
{
return aqlprofile_att_iterate_data(handle, callback, data);
Expand Down
Loading
Loading