[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
这个提交包含在:
+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 {
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
在新工单中引用
屏蔽一个用户