Dosyalar
rocm-systems/runtime/hsa-ext-aql-profile/src/aqlprofile/aql_profile.cpp
T
Evgeny 25035b8d09 Adding HSA extension AMD AQL profile library, see Readme.txt
Change-Id: Icbc1e0fb0185642eabbab411a2138ea030d22be8
2017-06-13 16:18:06 -04:00

399 satır
15 KiB
C++

#include <string>
#include "aql_profile.h"
#include "pm4_factory.h"
#include "cmdwriter.h" // commandwriter
#include "hsa_perf.h" // perfcounter
#include "thread_trace.h" // threadtrace
#include "gpu_enum.h"
#include "gpu_blockinfo.h"
#define PUBLIC_API __attribute__((visibility("default")))
namespace aql_profile {
// Command buffer partitioning manager
// Supports Pre/Post commands partitioning
// and postfix control partition
class CommandBufferMgr {
const static uint32_t align_size = 0x100;
const static uint32_t align_mask = align_size - 1;
struct info_t {
uint32_t precmds_size;
uint32_t postcmds_size;
};
descriptor_t buffer;
uint32_t postfix_size;
info_t* info;
uint32_t align(const uint32_t& size) { return (size + align_mask) & ~align_mask; }
public:
CommandBufferMgr(const profile_t* profile)
: buffer(profile->command_buffer), postfix_size(0), info(NULL) {
info = (info_t*)setPostfix(sizeof(info_t));
}
uint32_t getSize() { return buffer.size; }
void* setPostfix(const uint32_t& size) {
if (size > postfix_size) {
const uint32_t delta = size - postfix_size;
postfix_size = size;
buffer.size -= (delta < buffer.size) ? delta : buffer.size;
}
return (buffer.size != 0) ? buffer.ptr + buffer.size : NULL;
}
bool setPreSize(const uint32_t& size) {
bool suc = (size <= buffer.size);
if (suc) info->precmds_size = size;
return suc;
}
uint32_t getPostOffset() { return align(info->precmds_size); }
bool checkTotalSize(const uint32_t& size) {
bool suc = (size <= buffer.size);
if (suc) suc = (size >= info->precmds_size);
if (suc) {
info->postcmds_size = size - info->precmds_size;
suc = ((getPostOffset() + info->postcmds_size) <= buffer.size);
}
return suc;
}
descriptor_t getPreDescr() {
descriptor_t descr;
descr.ptr = buffer.ptr;
descr.size = info->precmds_size;
return descr;
}
descriptor_t getPostDescr() {
descriptor_t descr;
descr.ptr = buffer.ptr + getPostOffset();
descr.size = info->postcmds_size;
return descr;
}
};
static inline bool is_event_match(const event_t& event1, const event_t& event2) {
return (event1.block_name == event2.block_name) && (event1.block_index == event2.block_index) &&
(event1.counter_id == event2.counter_id);
}
hsa_status_t default_pmcdata_callback(hsa_ext_amd_aql_profile_info_type_t info_type,
hsa_ext_amd_aql_profile_info_data_t* info_data,
void* callback_data) {
hsa_status_t status = HSA_STATUS_SUCCESS;
hsa_ext_amd_aql_profile_info_data_t* passed_data =
reinterpret_cast<hsa_ext_amd_aql_profile_info_data_t*>(callback_data);
if (info_type == HSA_EXT_AQL_PROFILE_INFO_PMC_DATA) {
if (is_event_match(info_data->pmc_data.event, passed_data->pmc_data.event)) {
if (passed_data->sample_id == UINT32_MAX) {
passed_data->pmc_data.result += info_data->pmc_data.result;
} else if (passed_data->sample_id == info_data->sample_id) {
passed_data->pmc_data.result = info_data->pmc_data.result;
status = HSA_STATUS_INFO_BREAK;
}
}
}
return status;
}
struct sqtt_ctrl_t {
uint32_t status;
uint32_t counter;
uint32_t writePtr;
};
hsa_status_t default_sqttdata_callback(hsa_ext_amd_aql_profile_info_type_t info_type,
hsa_ext_amd_aql_profile_info_data_t* info_data,
void* callback_data) {
hsa_status_t status = HSA_STATUS_SUCCESS;
hsa_ext_amd_aql_profile_info_data_t* passed_data =
reinterpret_cast<hsa_ext_amd_aql_profile_info_data_t*>(callback_data);
if (info_type == HSA_EXT_AQL_PROFILE_INFO_SQTT_DATA) {
if (info_data->sample_id == passed_data->sample_id) {
passed_data->sqtt_data = info_data->sqtt_data;
status = HSA_STATUS_INFO_BREAK;
}
}
return status;
}
} // aql_profile
extern "C" {
// Check if event is valid for the specific GPU
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_validate_event(
hsa_agent_t agent, const hsa_ext_amd_aql_profile_event_t* event, bool* result) {
return HSA_STATUS_SUCCESS;
}
// Method to populate the provided AQL packet with profiling start commands
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_start(
const hsa_ext_amd_aql_profile_profile_t* profile, aql_profile::packet_t* aql_start_packet) {
aql_profile::Pm4Factory * pm4_factory = aql_profile::Pm4Factory::Create(profile);
if (pm4_factory == NULL) return HSA_STATUS_ERROR;
pm4_profile::CommandWriter* cmdWriter = pm4_factory->getCommandWriter();
if (cmdWriter == NULL) return HSA_STATUS_ERROR;
pm4_profile::DefaultCmdBuf commands;
aql_profile::CommandBufferMgr cmdBufMgr(profile);
if (cmdBufMgr.getSize() == 0) return HSA_STATUS_ERROR;
if (profile->type == HSA_EXT_AQL_PROFILE_EVENT_PMC) {
pm4_profile::Pmu* pmcMgr = pm4_factory->getPmcMgr();
if (pmcMgr == NULL) return HSA_STATUS_ERROR;
pmcMgr->setPmcDataBuff((uint8_t*)profile->output_buffer.ptr, profile->output_buffer.size);
for (const hsa_ext_amd_aql_profile_event_t* p = profile->events;
p < profile->events + profile->event_count; ++p) {
pm4_profile::CounterBlock* block =
pmcMgr->getCounterBlockById(pm4_factory->getBlockId(p));
if (block == NULL) return HSA_STATUS_ERROR;
pm4_profile::Counter* counter = block->createCounter();
if (counter == NULL) return HSA_STATUS_ERROR;
counter->setParameter(HSA_EXT_TOOLS_COUNTER_PARAMETER_EVENT_INDEX, sizeof(uint32_t),
&(p->counter_id));
counter->setEnable(true);
}
// Generate start commands
pmcMgr->begin(&commands, cmdWriter);
cmdBufMgr.setPreSize(commands.Size());
// Generate stop commands
pmcMgr->end(&commands, cmdWriter);
} else if (profile->type == HSA_EXT_AQL_PROFILE_EVENT_SQTT) {
pm4_profile::ThreadTrace* sqttMgr = pm4_factory->getSqttMgr();
if (sqttMgr == NULL) return HSA_STATUS_ERROR;
pm4_profile::ThreadTraceConfig sqtt_config;
sqttMgr->InitThreadTraceConfig(&sqtt_config);
if (profile->parameters) {
for (const hsa_ext_amd_aql_profile_parameters_t* p = profile->parameters;
p < (profile->parameters + profile->parameter_count); ++p) {
switch (p->parameter_name) {
case HSA_EXT_AQL_PROFILE_PARAM_COMPUTE_UNIT_TARGET:
sqtt_config.threadTraceTargetCu = p->value;
break;
case HSA_EXT_AQL_PROFILE_PARAM_VM_ID_MASK:
sqtt_config.threadTraceVmIdMask = p->value;
break;
case HSA_EXT_AQL_PROFILE_PARAM_MASK:
sqtt_config.threadTraceMask = p->value;
break;
case HSA_EXT_AQL_PROFILE_PARAM_TOKEN_MASK:
sqtt_config.threadTraceTokenMask = p->value;
break;
case HSA_EXT_AQL_PROFILE_PARAM_TOKEN_MASK2:
sqtt_config.threadTraceTokenMask2 = p->value;
break;
default:
return HSA_STATUS_ERROR;
}
}
}
sqttMgr->Init(&sqtt_config);
sqttMgr->setSqttDataBuff((uint8_t*)profile->output_buffer.ptr, profile->output_buffer.size);
const uint32_t status_size = sqttMgr->StatusSizeInfo();
void* status_ptr = cmdBufMgr.setPostfix(status_size);
if (status_ptr == NULL) return HSA_STATUS_ERROR;
// Control buffer registering
sqttMgr->setSqttCtrlBuff((uint32_t*)status_ptr);
// Generate start commands
sqttMgr->BeginSession(&commands, cmdWriter);
cmdBufMgr.setPreSize(commands.Size());
// Generate stop commands
sqttMgr->StopSession(&commands, cmdWriter);
} else
return HSA_STATUS_ERROR;
if (!cmdBufMgr.checkTotalSize(commands.Size())) return HSA_STATUS_ERROR;
const aql_profile::descriptor_t pre_descr = cmdBufMgr.getPreDescr();
const aql_profile::descriptor_t post_descr = cmdBufMgr.getPostDescr();
memcpy(pre_descr.ptr, commands.Base(), pre_descr.size);
memcpy(post_descr.ptr, commands.Base() + pre_descr.size, post_descr.size);
// Populate start aql packet
aql_profile::populateAql(pre_descr.ptr, pre_descr.size, cmdWriter, aql_start_packet);
return HSA_STATUS_SUCCESS;
}
// Method to populate the provided AQL packet with profiling stop commands
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_stop(
const hsa_ext_amd_aql_profile_profile_t* profile, aql_profile::packet_t* aql_stop_packet) {
aql_profile::Pm4Factory * pm4_factory = aql_profile::Pm4Factory::Create(profile);
if (pm4_factory == NULL) return HSA_STATUS_ERROR;
pm4_profile::CommandWriter* cmdWriter = pm4_factory->getCommandWriter();
if (cmdWriter == NULL) return HSA_STATUS_ERROR;
aql_profile::CommandBufferMgr cmdBufMgr(profile);
if (cmdBufMgr.getSize() == 0) return HSA_STATUS_ERROR;
const aql_profile::descriptor_t post_descr = cmdBufMgr.getPostDescr();
// Populate stop aql packet
aql_profile::populateAql(post_descr.ptr, post_descr.size, cmdWriter, aql_stop_packet);
return HSA_STATUS_SUCCESS;
}
// Converting of the profiling AQL packet to PM4 packet, GFX8 support
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_legacy_get_pm4(
const aql_profile::packet_t* aql_packet, void* pm4) {
return HSA_STATUS_ERROR;
}
// Method for getting the profile info
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_get_info(
const hsa_ext_amd_aql_profile_profile_t* profile, hsa_ext_amd_aql_profile_info_type_t attribute,
void* value) {
hsa_status_t status = HSA_STATUS_SUCCESS;
switch (attribute) {
case HSA_EXT_AQL_PROFILE_INFO_COMMAND_BUFFER_SIZE:
*(uint32_t*)value = 0x1000; // a current approximation as 4K is big enaugh
break;
case HSA_EXT_AQL_PROFILE_INFO_PMC_DATA_SIZE:
*(uint32_t*)value = 0x1000; // a current approximation as 4K is big enaugh
break;
case HSA_EXT_AQL_PROFILE_INFO_PMC_DATA:
reinterpret_cast<hsa_ext_amd_aql_profile_info_data_t*>(value)->pmc_data.result = 0;
status = hsa_ext_amd_aql_profile_iterate_data(profile, aql_profile::default_pmcdata_callback,
value);
break;
case HSA_EXT_AQL_PROFILE_INFO_SQTT_DATA:
status = hsa_ext_amd_aql_profile_iterate_data(profile, aql_profile::default_sqttdata_callback,
value);
break;
default:
status = HSA_STATUS_ERROR_INVALID_ARGUMENT;
}
return status;
}
// Method for iterating the events output data
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_iterate_data(
const hsa_ext_amd_aql_profile_profile_t* profile,
hsa_ext_amd_aql_profile_data_callback_t callback, void* data) {
hsa_status_t status = HSA_STATUS_SUCCESS;
aql_profile::Pm4Factory * pm4_factory = aql_profile::Pm4Factory::Create(profile);
if (pm4_factory == NULL) return HSA_STATUS_ERROR;
if (profile->type == HSA_EXT_AQL_PROFILE_EVENT_PMC) {
uint32_t info_size = 0;
void* info_data;
uint64_t* samples = (uint64_t*)profile->output_buffer.ptr;
const uint32_t sample_count = profile->output_buffer.size / sizeof(uint64_t);
uint32_t sample_index = 0;
pm4_profile::Pmu* pmcMgr = pm4_factory->getPmcMgr();
if (pmcMgr == NULL) return HSA_STATUS_ERROR;
for (const hsa_ext_amd_aql_profile_event_t* p = profile->events;
p < (profile->events + profile->event_count); ++p) {
pm4_profile::CounterBlock* block =
pmcMgr->getCounterBlockById(pm4_factory->getBlockId(p));
if (block == NULL) return HSA_STATUS_ERROR;
if (!block->getInfo(pm4_profile::GPU_BLK_INFO_CONTROL_METHOD, info_size, &info_data)) {
return HSA_STATUS_ERROR;
}
const pm4_profile::CntlMethod method =
static_cast<pm4_profile::CntlMethod>(*(static_cast<uint32_t*>(info_data)));
// A perfcounter data sample per ShaderEngine
const uint32_t block_samples_count = (method == pm4_profile::CntlMethodBySe ||
method == pm4_profile::CntlMethodBySeAndInstance)
? pmcMgr->getNumSe()
: 1;
for (uint32_t i = 0; i < block_samples_count; ++i) {
assert(sample_index < sample_count);
if (sample_index >= sample_count) return HSA_STATUS_ERROR;
hsa_ext_amd_aql_profile_info_data_t sample_info;
sample_info.sample_id = i;
sample_info.pmc_data.event = *p;
sample_info.pmc_data.result = samples[sample_index];
status = callback(HSA_EXT_AQL_PROFILE_INFO_PMC_DATA, &sample_info, data);
if (status == HSA_STATUS_INFO_BREAK) {
status = HSA_STATUS_SUCCESS;
break;
}
if (status != HSA_STATUS_SUCCESS) break;
++sample_index;
}
}
} else if (profile->type == HSA_EXT_AQL_PROFILE_EVENT_SQTT) {
pm4_profile::ThreadTrace* sqttMgr = pm4_factory->getSqttMgr();
if (sqttMgr == NULL) return HSA_STATUS_ERROR;
aql_profile::CommandBufferMgr cmdBufMgr(profile);
if (cmdBufMgr.getSize() == 0) return HSA_STATUS_ERROR;
const uint32_t status_size = sqttMgr->StatusSizeInfo();
// Control buffer was allocated as the CmdBuffer postfix partition
void* status_ptr = cmdBufMgr.setPostfix(status_size);
if (status_ptr == NULL) return HSA_STATUS_ERROR;
// Control buffer registering
sqttMgr->setSqttCtrlBuff((uint32_t*)status_ptr);
// Validate SQTT status and normalize WRPTR
if (sqttMgr->Validate() == false) return HSA_STATUS_ERROR;
const uint32_t se_number = sqttMgr->getNumSe();
// Casting status pointer to SQTT control per ShaderEngine array
aql_profile::sqtt_ctrl_t* sqtt_ctrl = (aql_profile::sqtt_ctrl_t*)status_ptr;
assert(status_size == sizeof(aql_profile::sqtt_ctrl_t) * se_number);
if (status_size != sizeof(aql_profile::sqtt_ctrl_t) * se_number) {
return HSA_STATUS_ERROR;
}
// SQTT output buffer and capacity per ShaderEngine
void* sample_ptr = profile->output_buffer.ptr;
const uint32_t sample_capacity = profile->output_buffer.size / se_number;
// The samples sizes are returned in the control buffer
for (int i = 0; i < se_number; ++i) {
// WPTR specifies the index in thread trace buffer where next token will be
// written by hardware. The index is incremented by size of 32 bytes.
uint32_t sample_size = sqtt_ctrl[i].writePtr * TT_WRITE_PTR_BLK;
hsa_ext_amd_aql_profile_info_data_t sample_info;
sample_info.sample_id = i;
sample_info.sqtt_data.ptr = sample_ptr;
sample_info.sqtt_data.size = sample_size;
status = callback(HSA_EXT_AQL_PROFILE_INFO_SQTT_DATA, &sample_info, data);
if (status == HSA_STATUS_INFO_BREAK) {
status = HSA_STATUS_SUCCESS;
break;
}
if (status != HSA_STATUS_SUCCESS) break;
sample_ptr += sample_capacity;
}
} else {
status = HSA_STATUS_ERROR;
}
return status;
}
}