[SPM] Clean up obsolete SPM logics and refine some SPM-related definition (#157)

* Clean up obsolete SPM logics
* Add PERFCOUNTER_SELECT1 to CounterRegInfo
* Add RLC_SPM_PERFMON_SAMPLE_DELAY_MAX
这个提交包含在:
Ma, Bing
2025-07-18 15:26:44 -07:00
提交者 GitHub
父节点 fdedcfc81c
当前提交 6f236ffb5f
共修改 20 个文件,包含 546 行新增和 1224 行删除
+11 -3
查看文件
@@ -52,10 +52,8 @@
}
// Getting SPM data using driver API
namespace spm_kfd_namespace {
hsa_status_t spm_iterate_data(const hsa_ven_amd_aqlprofile_profile_t* profile,
hsa_ven_amd_aqlprofile_data_callback_t callback, void* data);
}
// PC sampling callback data
struct pcsmp_callback_data_t {
@@ -255,6 +253,16 @@ PUBLIC_API hsa_status_t hsa_ven_amd_aqlprofile_start(hsa_ven_amd_aqlprofile_prof
pm4_builder::TraceConfig trace_config{};
const uint64_t se_number_total = pm4_factory->GetShaderEnginesNumber();
trace_config.spm_sq_32bit_mode = true;
trace_config.spm_has_core1 = (pm4_factory->GetGpuId() == aql_profile::MI100_GPU_ID) ||
(pm4_factory->GetGpuId() == aql_profile::MI200_GPU_ID);
trace_config.spm_sample_delay_max = pm4_factory->GetSpmSampleDelayMax();
trace_config.sampleRate = 1600;
trace_config.xcc_number = pm4_factory->GetXccNumber();
trace_config.se_number = se_number_total / trace_config.xcc_number;
trace_config.sa_number = pm4_factory->GetGpuId() >= aql_profile::GFX10_GPU_ID ? 2 : 0;
if (profile->parameters) {
for (const hsa_ven_amd_aqlprofile_parameter_t* p = profile->parameters;
p < (profile->parameters + profile->parameter_count); ++p) {
@@ -752,7 +760,7 @@ hsa_ven_amd_aqlprofile_iterate_data(const hsa_ven_amd_aqlprofile_profile_t* prof
sample_ptr = reinterpret_cast<char*>(sample_ptr) + sample_capacity;
}
} else {
status = spm_kfd_namespace::spm_iterate_data(profile, callback, data);
status = spm_iterate_data(profile, callback, data);
}
}
} else {
+2
查看文件
@@ -52,6 +52,8 @@ class Mi100Factory : public Gfx9Factory {
public:
explicit Mi100Factory(const AgentInfo* agent_info);
virtual uint32_t GetSpmSampleDelayMax() { return 0x34; }
protected:
static const GpuBlockInfo* block_table_[AQLPROFILE_BLOCKS_NUMBER];
};
+3
查看文件
@@ -152,6 +152,9 @@ class Pm4Factory {
// Return number of XCC on the GPU
uint32_t GetXccNumber() const { return agent_info_->xcc_num; }
// SPM specific
virtual uint32_t GetSpmSampleDelayMax() { return 0; }
const GpuBlockInfo* GetBlockInfo(const aqlprofile_pmc_event_t* event) const {
const GpuBlockInfo* info = block_map_.Get(event->block_name);
if (info == NULL) throw std::runtime_error("Bad Block");
-210
查看文件
@@ -20,220 +20,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <dirent.h>
#include "hsa/hsa_ext_amd.h"
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <atomic>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include "core/aql_profile.hpp"
#include "core/logger.h"
#include "core/pm4_factory.h"
#define PTHREAD_CALL(call) \
do { \
int err = call; \
if (err != 0) { \
errno = err; \
perror(#call); \
abort(); \
} \
} while (0)
namespace spm_kfd_namespace {
int get_gpu_node_id(uint32_t gpu_ind) {
int gpu_node = -1;
uint32_t index = 0;
// find a valid gpu node from /sys/class/kfd/kfd/topology/nodes
std::string path = "/sys/class/kfd/kfd/topology/nodes";
DIR* dir;
struct dirent* ent;
if ((dir = opendir(path.c_str())) != NULL) {
while ((ent = readdir(dir)) != NULL) {
std::string dir = ent->d_name;
if (dir.find_first_not_of("0123456789") == std::string::npos) {
std::string file = path + "/" + ent->d_name + "/gpu_id";
std::ifstream infile(file);
int id;
infile >> id;
if ((id != 0) && (index == gpu_ind)) {
++index;
gpu_node = atoi(ent->d_name);
break;
}
}
}
closedir(dir);
}
if (gpu_node == -1) {
printf("get_gpu_node_id`error: GPU[%d] not found\n", gpu_ind);
fflush(stdout);
abort();
}
return gpu_node;
}
int get_gpu_node_id(hsa_agent_t agent) {
const uint32_t gpu_ind = HsaRsrcFactory::Instance().GetAgentInfo(agent)->dev_index;
return get_gpu_node_id(gpu_ind);
}
struct state_t {
bool thread_stop;
int node_id;
uint32_t buf_size;
uint32_t timeout;
uint32_t data_size;
void* kfd_buf;
void* prod_buf;
void* cons_buf;
bool data_loss;
bool ready;
pthread_mutex_t work_mutex;
pthread_cond_t work_cond;
hsa_agent_t agent;
};
void producer_fun(state_t* state) {
uint32_t timeout = 0;
hsa_status_t status = HSA_STATUS_SUCCESS;
// hsa_amd_spm_set_dest_buffer(state->agent, state->buf_size, &timeout, &(state->data_size),
// state->kfd_buf, &(state->data_loss));
if (status != HSA_STATUS_SUCCESS) {
printf("hsa SPM Set DestBuffer init error\n");
fflush(stdout);
abort();
}
do {
timeout = state->timeout;
status = HSA_STATUS_SUCCESS;
// hsa_amd_spm_set_dest_buffer(state->agent, state->buf_size, &timeout, &(state->data_size),
// state->prod_buf, &(state->data_loss));
if (status != HSA_STATUS_SUCCESS) {
printf("hsa SPM Set DestBuffer error\n");
fflush(stdout);
abort();
}
PTHREAD_CALL(pthread_mutex_lock(&(state->work_mutex)));
void* tmp = state->prod_buf;
state->prod_buf = state->cons_buf;
state->cons_buf = state->kfd_buf;
state->kfd_buf = tmp;
state->ready = true;
PTHREAD_CALL(pthread_cond_signal(&(state->work_cond)));
PTHREAD_CALL(pthread_mutex_unlock(&(state->work_mutex)));
} while (!state->thread_stop);
status = HSA_STATUS_SUCCESS;
// hsa_amd_spm_set_dest_buffer(state->agent, 0, &timeout, &(state->data_size), NULL,
// &(state->data_loss));
if (status != HSA_STATUS_SUCCESS) {
printf("hsa SPM Set DestBuffer stop error\n");
fflush(stdout);
abort();
}
}
void consumer_fun(state_t* state, hsa_ven_amd_aqlprofile_data_callback_t callback, void* data) {
const uint32_t sample_id = 0;
PTHREAD_CALL(pthread_mutex_lock(&(state->work_mutex)));
do {
while (state->ready == false) {
PTHREAD_CALL(pthread_cond_wait(&(state->work_cond), &(state->work_mutex)));
}
state->ready = false;
hsa_ven_amd_aqlprofile_info_data_t sample_info;
sample_info.sample_id = sample_id;
sample_info.trace_data.ptr = state->cons_buf;
sample_info.trace_data.size = state->data_size;
hsa_status_t status = callback(HSA_VEN_AMD_AQLPROFILE_INFO_TRACE_DATA, &sample_info, data);
if (status == HSA_STATUS_INFO_BREAK) {
status = HSA_STATUS_SUCCESS;
state->thread_stop = true;
break;
} else if (status != HSA_STATUS_SUCCESS) {
printf("SPM consumer callback failed\n");
abort();
}
} while (1);
PTHREAD_CALL(pthread_mutex_unlock(&(state->work_mutex)));
}
void mananger_fun(const hsa_ven_amd_aqlprofile_profile_t* profile,
hsa_ven_amd_aqlprofile_data_callback_t callback, void* data) {
state_t obj{};
const int gpu_node_id = get_gpu_node_id(profile->agent);
char* buf_ptr = (char*)(profile->output_buffer.ptr);
// SPM data buffer size 256 byte aligned
const uint32_t buf_size = (profile->output_buffer.size / 3) & ~(uint32_t(256) - 1);
obj.timeout = 1000000; // 1sec
obj.node_id = gpu_node_id;
obj.buf_size = buf_size;
obj.kfd_buf = buf_ptr;
obj.prod_buf = buf_ptr + buf_size;
obj.cons_buf = buf_ptr + 2 * buf_size;
obj.agent = profile->agent;
PTHREAD_CALL(pthread_mutex_init(&(obj.work_mutex), NULL));
PTHREAD_CALL(pthread_cond_init(&(obj.work_cond), NULL));
hsa_status_t status = HSA_STATUS_SUCCESS; // hsa_amd_spm_acquire(profile->agent);
if (status != HSA_STATUS_SUCCESS) {
printf("hsa SPM Acquire error\n");
fflush(stdout);
abort();
}
// spm threads
std::thread producer(producer_fun, &obj);
std::thread consumer(consumer_fun, &obj, callback, data);
producer.join();
consumer.join();
status = HSA_STATUS_SUCCESS; // hsa_amd_spm_release(profile->agent);
if (status != HSA_STATUS_SUCCESS) {
printf("hsa SPM Release error\n");
fflush(stdout);
abort();
}
}
typedef std::mutex spm_mutex_t;
spm_mutex_t spm_mutex;
// Getting SPM data using driver API
hsa_status_t spm_iterate_data(const hsa_ven_amd_aqlprofile_profile_t* profile,
hsa_ven_amd_aqlprofile_data_callback_t callback, void* data) {
std::lock_guard<spm_mutex_t> lck(spm_mutex);
static std::thread* t = NULL;
if (t == NULL) {
// spm manager thread
t = new std::thread(mananger_fun, profile, callback, data);
} else {
t->join();
}
return HSA_STATUS_SUCCESS;
}
} // namespace spm_kfd_namespace
+6 -2
查看文件
@@ -80,13 +80,17 @@ struct CounterRegInfo {
Register register_addr_lo;
// counter register address high
Register register_addr_hi;
// counter select1 register address (for SPM)
Register select1_addr;
};
struct BlockDelayInfo {
Register reg;
uint32_t val;
const uint32_t* val; // Layout: val[SA][SE][instance]
};
#define BLOCK_DELAY_NONE { REG_32B_NULL, nullptr }
struct counter_des_t;
// GPU Block info definition
@@ -108,7 +112,7 @@ struct GpuBlockInfo {
// Block attributes mask
uint32_t attr;
// Block delay info
const BlockDelayInfo* delay_info;
BlockDelayInfo delay_info;
// SPM block id
uint32_t spm_block_id;
};
+1 -1
查看文件
@@ -330,7 +330,7 @@ class Gfx10CmdBuilder : public CmdBuilder {
}
void BuildNopPacket(CmdBuffer* cmdbuf, uint32_t num_dwords) {
uint32_t header = MakePacket3Header(PACKET3_NOP, num_dwords);
uint32_t header = MakePacket3Header(PACKET3_NOP, num_dwords * sizeof(uint32_t));
APPEND_COMMAND_WRAPPER(cmdbuf, header);
if (num_dwords > 1) {
std::vector<uint32_t> data_block((num_dwords - 1), 0);
+1 -1
查看文件
@@ -304,7 +304,7 @@ class Gfx11CmdBuilder : public CmdBuilder {
}
void BuildNopPacket(CmdBuffer* cmdbuf, uint32_t num_dwords) {
uint32_t header = MakePacket3Header(PACKET3_NOP, num_dwords);
uint32_t header = MakePacket3Header(PACKET3_NOP, num_dwords * sizeof(uint32_t));
APPEND_COMMAND_WRAPPER(cmdbuf, header);
if (num_dwords > 1) {
std::vector<uint32_t> data_block((num_dwords - 1), 0);
+1 -1
查看文件
@@ -325,7 +325,7 @@ class Gfx9CmdBuilder : public CmdBuilder {
}
void BuildNopPacket(CmdBuffer* cmdbuf, uint32_t num_dwords) {
uint32_t header = MakePacket3Header(PACKET3_NOP, num_dwords);
uint32_t header = MakePacket3Header(PACKET3_NOP, num_dwords * sizeof(uint32_t));
APPEND_COMMAND_WRAPPER(cmdbuf, header);
if (num_dwords > 1) {
std::vector<uint32_t> data_block((num_dwords - 1), 0);
+4 -18
查看文件
@@ -104,19 +104,6 @@ class GpuSpmBuilder : public SpmBuilder, protected Primitives {
// 3. Program the RLC_PERFMON_SEGMENT_SIZE register.
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::RLC_SPM_PERFMON_CNTL__ADDR,
Primitives::rlc_spm_perfmon_cntl_value(sampling_rate));
if (!config->spm_kfd_mode) {
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::RLC_SPM_PERFMON_RING_BASE_LO__ADDR,
buffer_ptr);
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::RLC_SPM_PERFMON_RING_BASE_HI__ADDR,
buffer_ptr >> 32);
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::RLC_SPM_PERFMON_RING_SIZE__ADDR,
buffer_size);
}
// Setting VMID
if (!config->spm_kfd_mode)
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::RLC_SPM_MC_CNTL__ADDR,
Primitives::rlc_spm_mc_cntl_value());
// Iterate through the list of blocks to create PM4 packets to read counter values
// Below pair.first is the block id of a counter event and pair.second is the index into
@@ -272,17 +259,16 @@ class GpuSpmBuilder : public SpmBuilder, protected Primitives {
for (size_t j = 0; j < block_info->instance_count; ++j) {
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::GRBM_GFX_INDEX_ADDR,
Primitives::grbm_inst_se_sh_index_value(j, 0, 0));
builder.BuildWriteUConfigRegPacket(cmd_buffer, block_info->delay_info[j].reg,
builder.BuildWriteUConfigRegPacket(cmd_buffer, block_info->delay_info.reg,
Primitives::get_spm_global_delay(counter_des, j));
}
} else {
for (size_t i = 0; i < config->spm_se_number_total; ++i) {
for (size_t i = 0; i < config->se_number; ++i) {
for (size_t j = 0; j < block_info->instance_count; ++j) {
int delay_index = i * block_info->instance_count + j;
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::GRBM_GFX_INDEX_ADDR,
Primitives::grbm_inst_se_index_value(j, i));
builder.BuildWriteUConfigRegPacket(cmd_buffer,
block_info->delay_info[delay_index].reg,
block_info->delay_info.reg,
Primitives::get_spm_se_delay(counter_des, i, j));
}
}
@@ -341,7 +327,7 @@ class GpuSpmBuilder : public SpmBuilder, protected Primitives {
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_SPM_PERFMON_SEGMENT_SIZE__ADDR,
Primitives::rlc_spm_perfmon_segment_size_value(global_count, se_count));
if (config->mi100) {
if (config->spm_has_core1) {
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_SPM_PERFMON_SEGMENT_SIZE_CORE1__ADDR,
Primitives::rlc_spm_perfmon_segment_size_core1_value(se_count));
+6 -4
查看文件
@@ -42,18 +42,20 @@ struct TraceConfig {
uint32_t perfMASK = ~0u;
uint32_t perfCTRL = 0;
std::vector<std::pair<size_t, size_t>> perfcounters{};
// GC configurations used by both TT and SPM
uint32_t se_number = 0;
uint32_t sa_number = 0;
uint32_t xcc_number = 0;
// SPM mode
bool spm_sq_32bit_mode = true;
bool spm_kfd_mode = true;
bool mi100 = false;
bool spm_has_core1 = false;
uint32_t spm_sample_delay_max = 0;
void* control_buffer_ptr = nullptr;
uint32_t control_buffer_size = 0;
void* data_buffer_ptr = nullptr;
uint32_t data_buffer_size = 0;
// SE number for tracing
uint32_t spm_se_number_total = 0;
// concurrent kernels mode
uint32_t concurrent = 0;
// SE mask for tracing; note -> replicated for all XCCs