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
20 changes: 20 additions & 0 deletions projects/rocprofiler-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,23 @@ Full documentation for ROCprofiler-SDK is available at [rocm.docs.amd.com/projec

### Removed
- Counter collection support for plain text (`.txt`) input files has been deprecated due to lack of schema validation and input sanitization. Only structured file formats (JSON and YAML) with schema validation are supported.

## ROCprofiler-SDK 1.3.0

### Added

- gfx1250 PMC support, including counter definitions and mappings for CHA, CHC, GLARBC, GL1A, GL1C, GRBMA, and GRBMH new blocks.
- gfx1250 ATT support with per-XCC trace configuration, buffer programming, token-mask updates, and trace readback for multi-XCC devices.
- Extended ATT waitcnt decode for async and tensor-related instructions, adding support for `s_wait_asynccnt` and `s_wait_tensorcnt`.
- gfx1250 stochastic PC sampling support:
- gfx1250-specific parser with sample routing.
- New stochastic sample fields: `sampling_lock_error`, `async_cnt`, `tensor_cnt`, `xnack_cnt`, and chiplet-aware metadata.
- Memory dependency counters reveal per-wave memory latency.
- Updated public PC sampling API structs and serialization for the new fields.
- Kernel/IOCTL enablement and dedicated gfx1250 parser tests.

### Changed

- Counter dimension encoding changed from fixed-width to variable-width allocation per dimension type.
- Dimension selection and reduction logic now uses explicit dimension masks and single-index selection.
- HSA queue interception extended to handle AMD extended kernel dispatch packets.
2 changes: 1 addition & 1 deletion projects/rocprofiler-sdk/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.3
1.3.0
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ function(rocprofiler_sdk_pc_sampling_stochastic_disabled _VAR)
list(GET rocprofiler-sdk-tests-gfx-info 0 pc-sampling-gpu-0-gfx-info)

if("${pc-sampling-gpu-0-gfx-info}" MATCHES "^gfx94[0-9]$"
OR "${pc-sampling-gpu-0-gfx-info}" MATCHES "^gfx95[0-9]$")
OR "${pc-sampling-gpu-0-gfx-info}" MATCHES "^gfx95[0-9]$"
OR "${pc-sampling-gpu-0-gfx-info}" MATCHES "^gfx1250$")
# PC sampling is enabled on this architecture.
set(${_VAR}
FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,44 @@ namespace codeobj
{
namespace disassembly
{
struct FallbackOp
{
const char* str{};
size_t size{};
};

inline FallbackOp
get_fallback_op_gfx1250(uint32_t header)
{
if((header >> 7) == 0) return {"v_vop_generic ", 4};

switch(header)
{
case 0b11001100: return {"v_vop3p_generic ", 8};
case 0b11001111: return {"v_vopd3_generic ", 12};
default: break;
}

header >>= 2;

switch(header)
{
case 0b110001: return {"buffer_load_generic ", 12};
case 0b111011: return {"global_load_generic ", 12};
case 0b110100: return {"image_load_generic ", 12};
case 0b110010: return {"v_vopd_generic ", 8};
case 0b110101: return {"v_vopsd_generic ", 8};
case 0b110110: return {"ds_generic ", 8};
case 0b111101: return {"s_load_generic ", 8};
default: break;
}

header >>= 4;
if(header == 0b10) return {"s_sop ", 4};

return {nullptr, 0};
}

class CodeObjectBinary
{
public:
Expand Down Expand Up @@ -206,6 +244,8 @@ class DisassemblyInstance
&DisassemblyInstance::inst_callback,
[](uint64_t, void*) {},
&info));

if(input_isa.find("gfx1250") != std::string::npos) gfxip = 1250;
}
~DisassemblyInstance()
{
Expand All @@ -218,8 +258,25 @@ class DisassemblyInstance
uint64_t size_read;
uint64_t addr_in_buffer = reinterpret_cast<uint64_t>(buffer.data()) + faddr;

THROW_COMGR(
amd_comgr_disassemble_instruction(info, addr_in_buffer, (void*) this, &size_read));
auto _status =
amd_comgr_disassemble_instruction(info, addr_in_buffer, (void*) this, &size_read);
if(_status != AMD_COMGR_STATUS_SUCCESS)
{
if(faddr + 4 > buffer.size()) THROW_COMGR(_status);

uint32_t read = 0;
std::memcpy(&read, buffer.data() + faddr, 4);

FallbackOp fallback{};

if(gfxip == 1250) fallback = get_fallback_op_gfx1250(read >> 24);

if(fallback.str == nullptr || fallback.size == 0) THROW_COMGR(_status);

this->last_instruction = fallback.str;
size_read = fallback.size;
}

return {std::move(this->last_instruction), size_read};
}

Expand Down Expand Up @@ -295,6 +352,7 @@ class DisassemblyInstance
return offset;
}

int gfxip{};
std::vector<char> buffer{};
std::string last_instruction{};
amd_comgr_disassembly_info_t info{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,9 @@ save(ArchiveT& ar, rocprofiler_pc_sampling_snapshot_v0_t data)
ROCP_SDK_SAVE_DATA_BITFIELD("arb_state_stall_exp", arb_state_stall_exp);
ROCP_SDK_SAVE_DATA_BITFIELD("arb_state_stall_misc", arb_state_stall_misc);
ROCP_SDK_SAVE_DATA_BITFIELD("arb_state_stall_brmsg", arb_state_stall_brmsg);

// sampling lock error
ROCP_SDK_SAVE_DATA_BITFIELD("lck_err", sampling_lock_error);
}

template <typename ArchiveT>
Expand All @@ -1070,6 +1073,9 @@ save(ArchiveT& ar, rocprofiler_pc_sampling_memory_counters_t data)
ROCP_SDK_SAVE_DATA_BITFIELD("sample_cnt", sample_cnt);
ROCP_SDK_SAVE_DATA_BITFIELD("ds_cnt", ds_cnt);
ROCP_SDK_SAVE_DATA_BITFIELD("km_cnt", km_cnt);
ROCP_SDK_SAVE_DATA_BITFIELD("async_cnt", async_cnt);
ROCP_SDK_SAVE_DATA_BITFIELD("tensor_cnt", tensor_cnt);
ROCP_SDK_SAVE_DATA_BITFIELD("xnack_cnt", xnack_cnt);
}

template <typename ArchiveT>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,9 @@ typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_snapshot_v0_
uint32_t arb_state_stall_brmsg : 1; ///< branch/message instruction was stalled
uint32_t arb_state_state_reserved : 1; ///< reserved for the future use
// We have two reserved bits
uint32_t dual_issue_valu : 1;
uint32_t reserved1 : 1; ///< reserved for the future use
uint32_t reserved2 : 3; ///< reserved for the future use
uint32_t dual_issue_valu : 1;
uint32_t sampling_lock_error : 1;
uint32_t reserved2 : 3; ///< reserved for the future use

/// @var reason_not_issued
/// @brief The reason for not issuing an instruction. The field takes one of the value defined
Expand All @@ -399,19 +399,28 @@ typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_snapshot_v0_
/// @brief VALU instruction was stalled when a sample was generated
/// @var dual_issue_valu
/// @brief Two VALU instructions were issued for coexecution (MI3xx specific)
/// @var sampling_lock_error
/// @brief At least one wave was locked out from taking a sample,
/// due to the latency instroduced by current sample read.
/// Too many samples with this bit on indicates that the sampling frequency is too high
} rocprofiler_pc_sampling_snapshot_v0_t;

/**
* @brief (experimental) Counters of issued but not yet completed instructions.
*/
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_memory_counters_t
{
uint32_t load_cnt : 6;
uint32_t store_cnt : 6;
uint32_t bvh_cnt : 3;
uint32_t sample_cnt : 6;
uint32_t ds_cnt : 6;
uint32_t km_cnt : 5;
uint64_t load_cnt : 6;
Comment thread
Sushma1203 marked this conversation as resolved.
Resolved
uint64_t store_cnt : 6;
uint64_t bvh_cnt : 3;
uint64_t sample_cnt : 6;
uint64_t ds_cnt : 6;
uint64_t km_cnt : 5;
// The following counters are relevant for gfx1250 only.
uint64_t async_cnt : 6;
uint64_t tensor_cnt : 6;
uint64_t xnack_cnt : 6;
uint64_t reserved : 14; ///< reserved for the future use

/// @var load_cnt
/// @brief Counts the number of VMEM load instructions issued but not yet completed.
Expand All @@ -426,6 +435,13 @@ typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_memory_count
/// @var km_cnt
/// @brief Counts the number of scalar memory reads and memory instructions issued but not yet
/// completed.
/// @var async_cnt
/// @brief Counts the number of async instructions issued but not yet completed.
/// @var tensor_cnt
/// @brief Counts the number of tensor instructions issued but not yet completed.
/// @var xnack_cnt
/// @brief Counts the number of oustanding memory instruction not yet reported
/// XNACK ackwlodgement.
} rocprofiler_pc_sampling_memory_counters_t;

/**
Expand Down
45 changes: 42 additions & 3 deletions projects/rocprofiler-sdk/source/lib/att-tool/waitcnt/gfx12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ enum MemoryInstType
TYPE_FLAT_LOAD,
TYPE_FLAT_STOR,
TYPE_BVH,
TYPE_TENSOR,
TYPE_ASYNC,
TYPE_WAITCNT
};

Expand All @@ -65,6 +67,8 @@ union MemoryInst
int stcnt : 1;
int sampl : 1;
int idle : 1;
int tensr : 1;
int async : 1;
};
int raw = 0;
};
Expand All @@ -82,21 +86,23 @@ classify(const std::string& inst)
{
if(inst.find("s_wait_alu") != npos) return MemoryInstType::TYPE_NOT_MEM;

MemoryInst type = MemoryInstType::TYPE_WAITCNT;

if(inst.find("s_wait_idle") != npos)
{
MemoryInst type = MemoryInstType::TYPE_WAITCNT;
type.idle = true;
type.idle = true;
return type;
}

MemoryInst type = MemoryInstType::TYPE_WAITCNT;
if(inst.find("dscnt") != npos) type.dscnt = true;
if(inst.find("bvhcnt") != npos) type.bvhcn = true;
if(inst.find("expcnt") != npos) type.expcn = true;
if(inst.find("kmcnt") != npos) type.kmcnt = true;
if(inst.find("loadcnt") != npos) type.ldcnt = true;
if(inst.find("storecnt") != npos) type.stcnt = true;
if(inst.find("samplecnt") != npos) type.sampl = true;
if(inst.find("asynccnt") != npos) type.async = true;
if(inst.find("tensorcnt") != npos) type.tensr = true;

return type;
}
Expand Down Expand Up @@ -130,6 +136,17 @@ classify(const std::string& inst)
else
return MemoryInstType::TYPE_LDS;
}
else if(inst.find("tensor_") <= 1)
{
return MemoryInstType::TYPE_TENSOR;
}
else if(inst.find("_async_") != npos)
{
if(inst.find("global_load_async_") == 0 || inst.find("global_store_async_") == 0)
{
return MemoryInstType::TYPE_ASYNC;
}
}

bool bStore = inst.find("store") != npos || inst.find("global_wb") == 0;

Expand All @@ -155,6 +172,8 @@ WaitcntList::gfx12_construct(const wave_t& wave, isa_map_t& isa_map)
MemoryCounter kmcnt("kmcnt");
MemoryCounter expcnt("expcnt");
MemoryCounter bvhcnt("bvhcnt");
MemoryCounter async("asynccnt");
MemoryCounter tensor("tensorcnt");

std::vector<int> flat_load{};
std::vector<int> flat_stor{};
Expand Down Expand Up @@ -231,6 +250,14 @@ WaitcntList::gfx12_construct(const wave_t& wave, isa_map_t& isa_map)
{
bvhcnt.list.push_back(line_number);
}
else if(type.inst == MemoryInstType::TYPE_TENSOR)
{
tensor.list.push_back(line_number);
}
else if(type.inst == MemoryInstType::TYPE_ASYNC)
{
async.list.push_back(line_number);
}
else if(type.inst == MemoryInstType::TYPE_WAITCNT)
{
if(type.bvhcn)
Expand Down Expand Up @@ -263,6 +290,16 @@ WaitcntList::gfx12_construct(const wave_t& wave, isa_map_t& isa_map)
if(auto joined = loadcnt.handle_mem_op(inst_str, flat_load))
mem_unroll.emplace_back(LineWaitcnt{line_number, std::move(*joined)});
}
if(type.tensr)
{
if(auto joined = tensor.handle_mem_op(inst_str, empty_list))
mem_unroll.emplace_back(LineWaitcnt{line_number, std::move(*joined)});
}
if(type.async)
{
if(auto joined = async.handle_mem_op(inst_str, empty_list))
mem_unroll.emplace_back(LineWaitcnt{line_number, std::move(*joined)});
}
if(type.dscnt)
{
if(auto joined = dscnt.handle_mem_op(inst_str, flat_load))
Expand All @@ -287,6 +324,8 @@ WaitcntList::gfx12_construct(const wave_t& wave, isa_map_t& isa_map)
kmcnt.clearTo(all);
expcnt.clearTo(all);
bvhcnt.clearTo(all);
tensor.clearTo(all);
async.clearTo(all);

mem_unroll.emplace_back(LineWaitcnt{line_number, std::move(all)});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,16 @@ TEST(att_decoder_waitcnt_test, gfx12)
append_isa(42, "s_wait_idle");
append_isa(43, "invalid");

append_isa(44, "global_load_async_");
append_isa(45, "global_store_async_");

append_isa(46, "tensor_load");
append_isa(47, "tensor_store");
append_isa(48, "tensor_save");

append_isa(49, "s_wait_tensorcnt 0");
append_isa(50, "s_wait_asynccnt 0");

std::vector<wave_instruction_t> insts{};
for(size_t i = 0; i < isa_map.size(); i++)
{
Expand Down Expand Up @@ -321,7 +331,7 @@ TEST(att_decoder_waitcnt_test, gfx12)
ASSERT_EQ(dependencies.at(dep).size(), set.size());
};

ASSERT_EQ(dependencies.size(), 12);
ASSERT_EQ(dependencies.size(), 14);
set_equal(6, {2, 3});
set_equal(7, {4});
set_equal(8, {5});
Expand All @@ -334,6 +344,8 @@ TEST(att_decoder_waitcnt_test, gfx12)
set_equal(38, {32, 33, 34, 35});
set_equal(39, {36});
set_equal(42, {40, 41});
set_equal(49, {46, 47, 48});
set_equal(50, {44, 45});
}

TEST(att_decoder_waitcnt_test, fail_conditions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,12 @@ construct_counter_collection_profile(rocprofiler_agent_id_t agent_id,

// search the gpu agent counter info for a counter with a matching name
bool counter_found = false;
for(const auto& citr : gpu_agents_counter_info.at(agent_id))
auto counter_vec = gpu_agents_counter_info.find(agent_id);
ROCP_FATAL_IF(counter_vec == gpu_agents_counter_info.end())
<< "No counter information found for agent " << agent_v->node_id << " (gpu-"
<< agent_v->gpu_index << ", " << agent_v->name << "). Unable to find counter: " << itr;

for(const auto& citr : counter_vec->second)
{
if(name_v == std::string_view{citr.name})
{
Expand Down
Loading
Loading