minor fixes, debug output, comments, using env vars, dead code

Change-Id: I08ad73b561709c1818d78a9191c96d6ad141a609


[ROCm/ROCR-Runtime commit: 8618bf7e2c]
Αυτή η υποβολή περιλαμβάνεται σε:
Evgeny
2017-06-14 18:47:01 -05:00
υποβλήθηκε από Evgeny Shcherbakov
γονέας 1351f204d4
υποβολή 9725267667
69 αρχεία άλλαξαν με 760 προσθήκες και 3417 διαγραφές
@@ -25,4 +25,6 @@ add_subdirectory ( ${TEST_DIR} ${PROJECT_BINARY_DIR}/test )
#
# Style format
#
execute_process ( COMMAND sh -xc "/usr/bin/find ${PROJ_DIR} ${TEST_DIR} ${API_DIR} -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -exec /usr/bin/clang-format -i -style=file \{\} \;" )
execute_process ( COMMAND sh -xc "/usr/bin/find ${PROJ_DIR} ${TEST_DIR} ${API_DIR} -name '*.cpp' -exec /usr/bin/clang-format -i -style=file \{\} \;" )
execute_process ( COMMAND sh -xc "/usr/bin/find ${PROJ_DIR} ${TEST_DIR} ${API_DIR} -name '*.hpp' -exec /usr/bin/clang-format -i -style=file \{\} \;" )
execute_process ( COMMAND sh -xc "/usr/bin/find ${PROJ_DIR} ${TEST_DIR} ${API_DIR} -name '*.h' -exec /usr/bin/clang-format -i -style=file \{\} \;" )
@@ -7,21 +7,19 @@ The library source tree:
- doc - Documantation, the API specification and the presentation
- inc - Public API
- hsa_ext_amd_aql_profile.h - AMD AQL profile library public API
- amd_aql_pm4_ib_packet.h - AQL PM4 IB packet type
- src - AMD AQL profile library sources
- aqlprofile - AMD AQL profile library
- commandwriter - PM4 command writer originated from 'hsa-runtime/tools'
- perfcounter - PM4 perfcounter manager originated from 'hsa-runtime/tools'
- threadtrace - PM4 threadtrace manager originated from 'hsa-runtime/tools'
- util - core/utils library build based on 'hsa-runtime/core/util'
- test - the library test suite
- ctrl - Test controll
- common - Test common utils
- util - Test utils
- SimpleConvolution - Simple convolution test
To build the library:
$ cd ..../hsa-ext-aql-profile
$ cd .../hsa-ext-aql-profile
$ mkdir build
$ cd build
$ cmake ..
@@ -29,12 +27,13 @@ $ make
To run the test:
# cd ..../hsa-ext-aql-profile/build
$ cp ../test/SimpleConvolution/gfx9_SimpleConvolution.hsaco .
$ test/SimpleConvolution
$ cd .../hsa-ext-aql-profile/build
$ test/ctrl
to enable PMC profiling:
export ROCR_ENABLE_PMC=1
To enable PMC profiling:
to enable SQTT profiling:
export ROCR_ENABLE_SQTT=1
$ export ROCR_ENABLE_PMC=1
To enable SQTT profiling:
$ export ROCR_ENABLE_SQTT=1
@@ -14,6 +14,8 @@
#ifndef _SI_PM4DEFS_H_
#define _SI_PM4DEFS_H_
#include "si_ci_vi_merged_typedef.h"
/******************************************************************************
*
* si_pm4defs.h
@@ -22,7 +22,9 @@
*
******************************************************************************/
#define COPY_DATA_SEL_COUNT_1DW 0 ///< Copy 1 word (32 bits)
#define COPY_DATA_SEL_REG 0 ///< Mem-mapped register
#define COPY_DATA_SEL_SRC_SYS_PERF_COUNTER 4 ///< Privileged memory performance counter
#define COPY_DATA_SEL_COUNT_1DW 0 ///< Copy 1 word (32 bits)
#define COPY_DATA_SEL_COUNT_2DW 1 ///< Copy 2 words (64 bits)
#endif // _GFX9_PM4DEFS_H_
@@ -202,9 +202,9 @@ hsa_status_t hsa_ext_amd_aql_profile_stop(
const hsa_ext_amd_aql_profile_profile_t* profile, // [in] profile contex object
hsa_ext_amd_aql_pm4_packet_t* aql_stop_packet); // [out] profile stop AQL packet
// Legacy PM4 profiling packet size
// Legacy devices, PM4 profiling packet size
const unsigned HSA_EXT_AQL_PROFILE_LEGACY_PM4_PACKET_SIZE = 192;
// GFX8 support, converting the profiling AQL packet to PM4 packet blob
// Legacy devices, converting the profiling AQL packet to PM4 packet blob
hsa_status_t hsa_ext_amd_aql_profile_legacy_get_pm4(
const hsa_ext_amd_aql_pm4_packet_t* aql_packet, // [in] AQL packet
void* data); // [out] PM4 packet blob
@@ -24,6 +24,7 @@ set ( API_DIR ${ROOT_DIR}/inc )
set ( HSA_RUNTIME_DIR ${PROJ_DIR}/../../.. )
set ( HSA_RUNTIME_OSC_DIR ${HSA_RUNTIME_DIR}/opensrc/hsa-runtime )
set ( CORE_UTIL_DIR ${HSA_RUNTIME_OSC_DIR}/core/util )
include_directories ( ${ROOT_DIR} )
#
@@ -36,13 +37,6 @@ include ( ${ROOT_DIR}/cmake_modules/validateBldEnv.cmake )
#
include ( ${ROOT_DIR}/cmake_modules/exportToolFlags.cmake )
#
# Set Name for Utils library and build it as a
# static library to be linked with others
#
set ( UTIL_LIB "util${ONLY64STR}" )
add_subdirectory ( ${PROJ_DIR}/util "${PROJECT_BINARY_DIR}/util" )
#
# Set Name for Cmdwriter library and build it as a
# static library to be linked with others
@@ -1,7 +1,7 @@
#
# Source files for Rocr Service Manager
#
set ( LIB_SRC aql_profile.cpp populate_aql.cpp gfx8_factory.cpp gfx9_factory.cpp )
set ( LIB_SRC aql_profile.cpp populate_aql.cpp gfx8_factory.cpp gfx9_factory.cpp legacy_pm4.cpp )
#
# Header files include path(s).
@@ -10,12 +10,11 @@ include_directories ( $ENV{ROCR_INC_DIR} )
include_directories ( ${PROJ_DIR}/perfcounter )
include_directories ( ${PROJ_DIR}/threadtrace )
include_directories ( ${PROJ_DIR}/commandwriter )
include_directories ( ${HSA_RUNTIME_OSC_DIR} )
include_directories ( ${API_DIR} )
#
# Build Service Manager as a dynamic Library object
#
set ( LIB_LIST ${PMC_LIB} ${SQTT_LIB} ${CMDWRITER_LIB} ${UTIL_LIB} )
set ( LIB_LIST ${PMC_LIB} ${SQTT_LIB} ${CMDWRITER_LIB} )
add_library ( ${TARGET_LIB} SHARED ${LIB_SRC} )
target_link_libraries( ${TARGET_LIB} ${LIB_LIST} c stdc++ dl pthread rt )
@@ -2,11 +2,10 @@
#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"
#include "cmdwriter.h" // commandwriter
#include "perf_counter.h" // perfcounter
#include "thread_trace.h" // threadtrace
#include "gpu_block_info.h"
#define PUBLIC_API __attribute__((visibility("default")))
@@ -129,6 +128,8 @@ hsa_status_t default_sqttdata_callback(hsa_ext_amd_aql_profile_info_type_t info_
return status;
}
Pm4Factory::tables_t Pm4Factory::tables;
} // aql_profile
extern "C" {
@@ -142,8 +143,7 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_validate_event(
// 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);
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();
@@ -157,27 +157,22 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_start(
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);
pm4_profile::CountersMap countersMap;
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);
countersMap[pm4_factory->getBlockId(p)].push_back(p->counter_id);
}
// Generate start commands
pmcMgr->begin(&commands, cmdWriter);
pmcMgr->begin(&commands, cmdWriter, countersMap);
cmdBufMgr.setPreSize(commands.Size());
// Generate stop commands
pmcMgr->end(&commands, cmdWriter);
const uint32_t data_size =
pmcMgr->end(&commands, cmdWriter, countersMap, profile->output_buffer.ptr);
if (data_size == 0) return HSA_STATUS_ERROR;
assert(data_size <= profile->output_buffer.size);
if (data_size > profile->output_buffer.size) return HSA_STATUS_ERROR;
} else if (profile->type == HSA_EXT_AQL_PROFILE_EVENT_SQTT) {
pm4_profile::ThreadTrace* sqttMgr = pm4_factory->getSqttMgr();
if (sqttMgr == NULL) return HSA_STATUS_ERROR;
@@ -241,8 +236,7 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_start(
// 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);
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();
@@ -258,9 +252,9 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_stop(
return HSA_STATUS_SUCCESS;
}
// GFX8 support, converting of the profiling AQL packet to PM4 packet blob
PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_legacy_get_pm4(
const aql_profile::packet_t* aql_packet, void* data) {
// Legacy devices, converting of the profiling AQL packet to PM4 packet blob
PUBLIC_API hsa_status_t
hsa_ext_amd_aql_profile_legacy_get_pm4(const aql_profile::packet_t* aql_packet, void* data) {
// Populate GFX8 pm4 packet blob
// Adding HSA barrier acquire packet
data = aql_profile::legacyAqlAcquire(aql_packet, data);
@@ -272,9 +266,9 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_legacy_get_pm4(
}
// 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) {
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) {
@@ -301,12 +295,11 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_get_info(
}
// 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) {
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);
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) {
@@ -321,14 +314,9 @@ PUBLIC_API hsa_status_t hsa_ext_amd_aql_profile_iterate_data(
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)));
const pm4_profile::GpuBlockInfo* block_info = pm4_factory->getBlockInfo(p);
if (block_info == NULL) return HSA_STATUS_ERROR;
const pm4_profile::CntlMethod method = pm4_factory->getBlockInfo(p)->method;
// A perfcounter data sample per ShaderEngine
const uint32_t block_samples_count = (method == pm4_profile::CntlMethodBySe ||
method == pm4_profile::CntlMethodBySeAndInstance)
@@ -16,7 +16,7 @@ typedef hsa_ext_amd_aql_profile_data_callback_t data_callback_t;
typedef hsa_ext_amd_aql_pm4_packet_t packet_t;
typedef hsa_ext_amd_aql_profile_event_t event_t;
void populateAql(void* cmdBuffer, uint32_t cmdSz, pm4_profile::CommandWriter* cmdWriter,
void populateAql(const void* cmd_buffer, uint32_t cmd_size, pm4_profile::CommandWriter* cmd_writer,
packet_t* aql_packet);
void* legacyAqlAcquire(const packet_t* aql_packet, void* data);
void* legacyAqlRelease(const packet_t* aql_packet, void* data);
@@ -2,9 +2,11 @@
// Commandwriter includes
#include "gfx8_cmdwriter.h"
// PMC includes
#include "vi_pmu.h"
#include "gfx8_perf_counter.h"
// SQTT includes
#include "gfx8_thread_trace.h"
// Block info
#include "gfx8_block_info.h"
namespace aql_profile {
@@ -24,20 +26,12 @@ uint32_t Gfx8Factory::block_id_table[HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER] = {
pm4_profile::kHsaViCounterBlockIdIa, pm4_profile::kHsaViCounterBlockIdMc,
pm4_profile::kHsaViCounterBlockIdTcs, pm4_profile::kHsaViCounterBlockIdWd};
pm4_profile::CommandWriter * Gfx8Factory::getCommandWriter() {
pm4_profile::CommandWriter* Gfx8Factory::getCommandWriter() {
return new pm4_profile::gfx8::Gfx8CmdWriter(false, true);
}
pm4_profile::Pmu * Gfx8Factory::getPmcMgr() {
return new pm4_profile::ViPmu();
}
pm4_profile::Pmu* Gfx8Factory::getPmcMgr() { return new pm4_profile::Gfx8PerfCounter(); }
pm4_profile::ThreadTrace * Gfx8Factory::getSqttMgr() {
return new pm4_profile::Gfx8ThreadTrace();
}
pm4_profile::ThreadTrace* Gfx8Factory::getSqttMgr() { return new pm4_profile::Gfx8ThreadTrace(); }
uint32_t Gfx8Factory::getBlockId(const event_t* event) {
return block_id_table[event->block_name] + event->block_index;
}
} // aql_profile
} // aql_profile
@@ -1,70 +0,0 @@
#include "pm4_factory.h"
// Commandwriter includes
#include "gfx8_cmdwriter.h"
#include "gfx9_cmdwriter.h"
// PMC includes
#include "vi_pmu.h"
#include "ai_pmu.h"
// SQTT includes
#include "gfx8_thread_trace.h"
#include "gfx9_thread_trace.h"
namespace aql_profile {
// GFX8 block ID mapping table
uint32_t gfx8_block_id_table[HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER] = {
pm4_profile::kHsaViCounterBlockIdCb0, pm4_profile::kHsaViCounterBlockIdCpf,
pm4_profile::kHsaViCounterBlockIdDb0, pm4_profile::kHsaViCounterBlockIdGrbm,
pm4_profile::kHsaViCounterBlockIdGrbmSe, pm4_profile::kHsaViCounterBlockIdPaSu,
pm4_profile::kHsaViCounterBlockIdPaSc, pm4_profile::kHsaViCounterBlockIdSpi,
pm4_profile::kHsaViCounterBlockIdSq, pm4_profile::kHsaViCounterBlockIdSqGs,
pm4_profile::kHsaViCounterBlockIdSqVs, pm4_profile::kHsaViCounterBlockIdSqPs,
pm4_profile::kHsaViCounterBlockIdSqHs, pm4_profile::kHsaViCounterBlockIdSqCs,
pm4_profile::kHsaViCounterBlockIdSx, pm4_profile::kHsaViCounterBlockIdTa0,
pm4_profile::kHsaViCounterBlockIdTca0, pm4_profile::kHsaViCounterBlockIdTcc0,
pm4_profile::kHsaViCounterBlockIdTd0, pm4_profile::kHsaViCounterBlockIdTcp0,
pm4_profile::kHsaViCounterBlockIdGds, pm4_profile::kHsaViCounterBlockIdVgt,
pm4_profile::kHsaViCounterBlockIdIa, pm4_profile::kHsaViCounterBlockIdMc,
pm4_profile::kHsaViCounterBlockIdTcs, pm4_profile::kHsaViCounterBlockIdWd};
// GFX9 block ID mapping table
uint32_t gfx9_block_id_table[HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER] = {
pm4_profile::kHsaAiCounterBlockIdCb0, pm4_profile::kHsaAiCounterBlockIdCpf,
pm4_profile::kHsaAiCounterBlockIdDb0, pm4_profile::kHsaAiCounterBlockIdGrbm,
pm4_profile::kHsaAiCounterBlockIdGrbmSe, pm4_profile::kHsaAiCounterBlockIdPaSu,
pm4_profile::kHsaAiCounterBlockIdPaSc, pm4_profile::kHsaAiCounterBlockIdSpi,
pm4_profile::kHsaAiCounterBlockIdSq, pm4_profile::kHsaAiCounterBlockIdSqGs,
pm4_profile::kHsaAiCounterBlockIdSqVs, pm4_profile::kHsaAiCounterBlockIdSqPs,
pm4_profile::kHsaAiCounterBlockIdSqHs, pm4_profile::kHsaAiCounterBlockIdSqCs,
pm4_profile::kHsaAiCounterBlockIdSx, pm4_profile::kHsaAiCounterBlockIdTa0,
pm4_profile::kHsaAiCounterBlockIdTca0, pm4_profile::kHsaAiCounterBlockIdTcc0,
pm4_profile::kHsaAiCounterBlockIdTd0, pm4_profile::kHsaAiCounterBlockIdTcp0,
pm4_profile::kHsaAiCounterBlockIdGds, pm4_profile::kHsaAiCounterBlockIdVgt,
pm4_profile::kHsaAiCounterBlockIdIa, pm4_profile::kHsaAiCounterBlockIdMc,
pm4_profile::kHsaAiCounterBlockIdTcs, pm4_profile::kHsaAiCounterBlockIdWd};
pm4_profile::CommandWriter * Pm4Factory::getCommandWriter() {
return (is_gfx9 == true) ?
new pm4_profile::gfx9::Gfx9CmdWriter(false, true) :
new pm4_profile::gfx8::Gfx8CmdWriter(false, true);
}
pm4_profile::Pmu * Pm4Factory::getPmcMgr() {
return (is_gfx9 == true) ?
new pm4_profile::AiPmu() :
new pm4_profile::ViPmu();
}
pm4_profile::ThreadTrace * Pm4Factory::getSqttMgr() {
return (is_gfx9 == true) ?
new pm4_profile::Gfx9ThreadTrace() :
new pm4_profile::Gfx8ThreadTrace();
}
uint32_t Pm4Factory::getBlockId(const event_t* event) {
return (is_gfx9 == true) ?
gfx9_block_id_table[event->block_name] + event->block_index :
gfx8_block_id_table[event->block_name] + event->block_index :
}
} // aql_profile
@@ -2,9 +2,11 @@
// Commandwriter includes
#include "gfx9_cmdwriter.h"
// PMC includes
#include "ai_pmu.h"
#include "gfx9_perf_counter.h"
// SQTT includes
#include "gfx9_thread_trace.h"
// Block info
#include "gfx9_block_info.h"
namespace aql_profile {
@@ -24,20 +26,12 @@ uint32_t Gfx9Factory::block_id_table[HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER] = {
pm4_profile::kHsaAiCounterBlockIdIa, pm4_profile::kHsaAiCounterBlockIdMc,
pm4_profile::kHsaAiCounterBlockIdTcs, pm4_profile::kHsaAiCounterBlockIdWd};
pm4_profile::CommandWriter * Gfx9Factory::getCommandWriter() {
pm4_profile::CommandWriter* Gfx9Factory::getCommandWriter() {
return new pm4_profile::gfx9::Gfx9CmdWriter(false, true);
}
pm4_profile::Pmu * Gfx9Factory::getPmcMgr() {
return new pm4_profile::AiPmu();
}
pm4_profile::Pmu* Gfx9Factory::getPmcMgr() { return new pm4_profile::Gfx9PerfCounter(); }
pm4_profile::ThreadTrace * Gfx9Factory::getSqttMgr() {
return new pm4_profile::Gfx9ThreadTrace();
}
pm4_profile::ThreadTrace* Gfx9Factory::getSqttMgr() { return new pm4_profile::Gfx9ThreadTrace(); }
uint32_t Gfx9Factory::getBlockId(const event_t* event) {
return block_id_table[event->block_name] + event->block_index;
}
} // aql_profile
} // aql_profile
@@ -0,0 +1,96 @@
#include <iostream>
#include <sstream>
#include <iomanip>
#include <assert.h>
#include <string.h>
#include "aql_profile.h"
#include "amd_aql_pm4_ib_packet.h"
#include "gfxip/gfx8/si_pm4defs.h"
#include "gfxip/gfx8/si_ci_vi_merged_pm4_it_opcodes.h"
#include "gfxip/gfx8/si_ci_vi_merged_pm4cmds.h"
namespace aql_profile {
typedef uint16_t aql_packet_header_t;
void* legacyAqlAcquire(const packet_t* aql_packet, void* data) {
hsa_barrier_and_packet_t* aql_barrier = reinterpret_cast<hsa_barrier_and_packet_t*>(data);
memset(aql_barrier, 0, sizeof(hsa_barrier_and_packet_t));
const aql_packet_header_t aql_header_type = HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
const aql_packet_header_t aql_header_barrier = 1ul << HSA_PACKET_HEADER_BARRIER;
const aql_packet_header_t aql_header_acquire = HSA_FENCE_SCOPE_SYSTEM
<< HSA_PACKET_HEADER_SCACQUIRE_FENCE_SCOPE;
aql_barrier->header |= aql_header_type;
aql_barrier->header |= aql_header_barrier;
aql_barrier->header |= aql_header_acquire;
return data + sizeof(hsa_barrier_and_packet_t);
}
void* legacyAqlRelease(const packet_t* aql_packet, void* data) {
hsa_barrier_and_packet_t* aql_barrier = reinterpret_cast<hsa_barrier_and_packet_t*>(data);
memset(aql_barrier, 0, sizeof(hsa_barrier_and_packet_t));
const aql_packet_header_t aql_header_type = HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
const aql_packet_header_t aql_header_barrier = 1ul << HSA_PACKET_HEADER_BARRIER;
const aql_packet_header_t aql_header_release = HSA_FENCE_SCOPE_SYSTEM
<< HSA_PACKET_HEADER_SCRELEASE_FENCE_SCOPE;
aql_barrier->header |= aql_header_type;
aql_barrier->header |= aql_header_barrier;
aql_barrier->header |= aql_header_release;
aql_barrier->completion_signal = aql_packet->completion_signal;
return data + sizeof(hsa_barrier_and_packet_t);
}
void* legacyPm4(const packet_t* aql_packet, void* data) {
constexpr uint32_t major_version = 8;
constexpr uint32_t slot_size_b = 0x40;
constexpr uint32_t slot_size_dw = uint32_t(slot_size_b / sizeof(uint32_t));
constexpr uint32_t ib_jump_size_dw = 4;
constexpr uint32_t rel_mem_size_dw = 7;
constexpr uint32_t nop_pad_size_dw = slot_size_dw - (ib_jump_size_dw + rel_mem_size_dw);
// Construct a set of PM4 to fit inside the AQL packet slot.
const amd_aql_pm4_ib_packet_t* aql_pm4_ib =
reinterpret_cast<const amd_aql_pm4_ib_packet_t*>(aql_packet);
uint32_t* const slot_data = (uint32_t*)data;
uint32_t slot_dw_idx = 0;
// Construct a no-op command to pad the queue slot.
uint32_t* nop_pad = &slot_data[slot_dw_idx];
slot_dw_idx += nop_pad_size_dw;
nop_pad[0] = PM4_CMD(IT_NOP, nop_pad_size_dw);
for (int i = 1; i < nop_pad_size_dw; ++i) {
nop_pad[i] = 0;
}
// Copy in command to execute the IB.
assert(slot_dw_idx + ib_jump_size_dw <= slot_size_dw);
uint32_t* ib_jump = &slot_data[slot_dw_idx];
slot_dw_idx += ib_jump_size_dw;
assert(ib_jump_size_dw == sizeof(aql_pm4_ib->pm4_ib_command) / sizeof(uint32_t));
memcpy(ib_jump, aql_pm4_ib->pm4_ib_command, sizeof(aql_pm4_ib->pm4_ib_command));
// Construct a command to advance the read index and invalidate the packet
// header. This must be the last command since this releases the queue slot
// for writing.
assert(slot_dw_idx + rel_mem_size_dw <= slot_size_dw);
PM4CMDRELEASEMEM* rel_mem = reinterpret_cast<PM4CMDRELEASEMEM*>(&slot_data[slot_dw_idx]);
assert(rel_mem_size_dw == sizeof(*rel_mem) / sizeof(uint32_t));
memset(rel_mem, 0, sizeof(*rel_mem));
rel_mem->ordinal1 = PM4_CMD(IT_RELEASE_MEM__CI__VI, rel_mem_size_dw);
rel_mem->eventIndex = EVENT_WRITE_INDEX_CACHE_FLUSH_EVENT;
#if !defined(NDEBUG)
std::ostringstream oss;
oss << "AQL 'Legacy PM4' size(" << slot_size_dw << ")";
std::clog << std::setw(40) << std::left << oss.str() << ":";
for (int idx = 0; idx < 16; idx++) {
std::clog << " " << std::hex << std::setw(8) << std::setfill('0') << slot_data[idx];
}
std::clog << std::setfill(' ') << std::endl;
#endif
return data + slot_size_b;
}
} // aql_profile
@@ -3,13 +3,20 @@
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <climits>
#include "aql_profile.h"
#include "gpu_block_info.h"
namespace pm4_profile {
class CommandWriter;
class Pmu;
class ThreadTrace;
extern GpuBlockInfo Gfx9HwBlocks[];
extern const uint32_t Gfx9HwBlockCount;
extern GpuBlockInfo Gfx8HwBlocks[];
extern const uint32_t Gfx8HwBlockCount;
}
namespace aql_profile {
@@ -20,15 +27,63 @@ class Pm4Factory {
virtual pm4_profile::CommandWriter* getCommandWriter() = 0;
virtual pm4_profile::Pmu* getPmcMgr() = 0;
virtual pm4_profile::ThreadTrace* getSqttMgr() = 0;
virtual uint32_t getBlockId(const event_t* event) = 0;
uint32_t getBlockId(const event_t* event) {
const hsa_ext_amd_aql_profile_block_name_t block_name = event->block_name;
return (block_name < tables.get_block_id_count())
? tables.get_block_id_ptr()[block_name] + event->block_index
: UINT_MAX;
}
const pm4_profile::GpuBlockInfo* getBlockInfo(const uint32_t& block_id) {
const pm4_profile::GpuBlockInfo* info = NULL;
if (block_id < tables.get_block_info_count()) {
info = tables.get_block_info_ptr() + block_id;
if (info->counterGroupId != block_id) info = NULL;
}
return info;
}
const pm4_profile::GpuBlockInfo* getBlockInfo(const event_t* event) {
const uint32_t block_id = getBlockId(event);
return getBlockInfo(block_id);
}
protected:
class tables_t {
public:
tables_t(uint32_t* dp, uint32_t dc, pm4_profile::GpuBlockInfo* ip, uint32_t ic)
: block_id_ptr(dp), block_id_count(dc), block_info_ptr(ip), block_info_count(ic) {}
tables_t(const tables_t& t)
: block_id_ptr(t.block_id_ptr),
block_id_count(t.block_id_count),
block_info_ptr(t.block_info_ptr),
block_info_count(t.block_info_count) {}
tables_t() : block_id_ptr(0), block_id_count(0), block_info_ptr(0), block_info_count(0) {}
uint32_t* get_block_id_ptr() { return block_id_ptr; }
uint32_t get_block_id_count() { return block_id_count; }
pm4_profile::GpuBlockInfo* get_block_info_ptr() { return block_info_ptr; }
uint32_t get_block_info_count() { return block_info_count; }
private:
uint32_t* block_id_ptr;
uint32_t block_id_count;
pm4_profile::GpuBlockInfo* block_info_ptr;
uint32_t block_info_count;
};
Pm4Factory(const tables_t& t) { tables = t; }
static tables_t tables;
};
class Gfx8Factory : public Pm4Factory {
public:
Gfx8Factory()
: Pm4Factory(tables_t(block_id_table, HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER,
pm4_profile::Gfx8HwBlocks, pm4_profile::Gfx8HwBlockCount)) {}
pm4_profile::CommandWriter* getCommandWriter();
pm4_profile::Pmu* getPmcMgr();
pm4_profile::ThreadTrace* getSqttMgr();
uint32_t getBlockId(const event_t* event);
private:
static uint32_t block_id_table[HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER];
@@ -36,10 +91,12 @@ class Gfx8Factory : public Pm4Factory {
class Gfx9Factory : public Pm4Factory {
public:
Gfx9Factory()
: Pm4Factory(tables_t(block_id_table, HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER,
pm4_profile::Gfx9HwBlocks, pm4_profile::Gfx9HwBlockCount)) {}
pm4_profile::CommandWriter* getCommandWriter();
pm4_profile::Pmu* getPmcMgr();
pm4_profile::ThreadTrace* getSqttMgr();
uint32_t getBlockId(const event_t* event);
private:
static uint32_t block_id_table[HSA_EXT_AQL_PROFILE_BLOCKS_NUMBER];
@@ -49,11 +106,13 @@ inline Pm4Factory* Pm4Factory::Create(const hsa_ext_amd_aql_profile_profile_t* p
Pm4Factory* instance = NULL;
char agent_name[64];
hsa_agent_get_info(profile->agent, HSA_AGENT_INFO_NAME, agent_name);
if (strncmp(agent_name, "gfx8", 4) == 0) {
instance = new Gfx8Factory();
} else if (strncmp(agent_name, "gfx9", 4) == 0) {
instance = new Gfx9Factory();
}
return instance;
}
@@ -1,96 +1,15 @@
#include <iostream>
#include <sstream>
#include <iomanip>
#include <assert.h>
#include "aql_profile.h"
#include "cmdwriter.h"
#include "amd_aql_pm4_ib_packet.h"
#include "core/inc/amd_gpu_pm4.h"
namespace aql_profile {
typedef uint16_t aql_packet_header_t;
void * legacyAqlAcquire(const packet_t* aql_packet, void * data) {
hsa_barrier_and_packet_t * aql_barrier =
reinterpret_cast<hsa_barrier_and_packet_t*>(data);
memset(aql_barrier, 0 , sizeof(hsa_barrier_and_packet_t));
const aql_packet_header_t aql_header_type =
HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
const aql_packet_header_t aql_header_barrier =
1ul << HSA_PACKET_HEADER_BARRIER;
aql_barrier->header |= aql_header_type;
aql_barrier->header |= aql_header_barrier;
return data + sizeof(hsa_barrier_and_packet_t);
}
void * legacyAqlRelease(const packet_t* aql_packet, void * data) {
hsa_barrier_and_packet_t * aql_barrier =
reinterpret_cast<hsa_barrier_and_packet_t*>(data);
memset(aql_barrier, 0 , sizeof(hsa_barrier_and_packet_t));
const aql_packet_header_t aql_header_type =
HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
const aql_packet_header_t aql_header_barrier =
1ul << HSA_PACKET_HEADER_BARRIER;
const aql_packet_header_t aql_header_release =
HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_SCRELEASE_FENCE_SCOPE;
aql_barrier->header |= aql_header_type;
aql_barrier->header |= aql_header_barrier;
aql_barrier->header |= aql_header_release;
aql_barrier->completion_signal = aql_packet->completion_signal;
return data + sizeof(hsa_barrier_and_packet_t);
}
void * legacyPm4(const packet_t* aql_packet, void *data) {
constexpr uint32_t major_version = 8;
constexpr uint32_t slot_size_b = 0x40;
constexpr uint32_t ib_jump_size_dw = 4;
constexpr uint32_t slot_size_dw = uint32_t(slot_size_b / sizeof(uint32_t));
const amd_aql_pm4_ib_packet_t* aql_pm4_ib =
reinterpret_cast<const amd_aql_pm4_ib_packet_t*>(aql_packet);
uint32_t * slot_data = (uint32_t*)data;
// Construct a set of PM4 to fit inside the AQL packet slot.
uint32_t slot_dw_idx = 0;
// Construct a no-op command to pad the queue slot.
constexpr uint32_t rel_mem_size_dw = 7;
constexpr uint32_t nop_pad_size_dw = slot_size_dw - (ib_jump_size_dw + rel_mem_size_dw);
uint32_t* nop_pad = &slot_data[slot_dw_idx];
slot_dw_idx += nop_pad_size_dw;
nop_pad[0] = PM4_HDR(PM4_HDR_IT_OPCODE_NOP, nop_pad_size_dw, major_version);
for (int i = 1; i < nop_pad_size_dw; ++i) {
nop_pad[i] = 0;
}
// Copy in command to execute the IB.
assert(slot_dw_idx + ib_jump_size_dw <= slot_size_dw && "PM4 exceeded queue slot size");
uint32_t* ib_jump = &slot_data[slot_dw_idx];
slot_dw_idx += ib_jump_size_dw;
memcpy(ib_jump, aql_pm4_ib->pm4_ib_command, sizeof(aql_pm4_ib->pm4_ib_command));
// Construct a command to advance the read index and invalidate the packet
// header. This must be the last command since this releases the queue slot
// for writing.
assert(slot_dw_idx + rel_mem_size_dw <= slot_size_dw && "PM4 exceeded queue slot size");
uint32_t* rel_mem = &slot_data[slot_dw_idx];
rel_mem[0] =
PM4_HDR(PM4_HDR_IT_OPCODE_RELEASE_MEM, rel_mem_size_dw, major_version);
rel_mem[1] = PM4_RELEASE_MEM_DW1_EVENT_INDEX(PM4_RELEASE_MEM_EVENT_INDEX_AQL);
rel_mem[2] = 0;
rel_mem[3] = 0;
rel_mem[4] = 0;
rel_mem[5] = 0;
rel_mem[6] = 0;
return data + slot_size_b;
}
void populateAql(uint32_t* ib_packet, packet_t* aql_packet) {
void populateAql(const uint32_t* ib_packet, packet_t* aql_packet) {
// Populate relevant fields of Aql pkt
// Size of IB pkt is four DWords
// Header and completion sinal are not set
@@ -105,20 +24,25 @@ void populateAql(uint32_t* ib_packet, packet_t* aql_packet) {
aql_pm4_ib->reserved[i] = 0;
}
uint32_t* words = (uint32_t*)aql_packet;
#if !defined(NDEBUG)
const uint32_t* dwords = (uint32_t*)aql_packet;
const uint32_t dword_count = sizeof(*aql_packet) / sizeof(uint32_t);
std::ostringstream oss;
oss << "AQL 'IB' size(" << dword_count << ")";
std::clog << std::setw(40) << std::left << "AQL 'IB' size(16)"
<< ":";
for (int idx = 0; idx < 16; idx++) {
std::clog << " " << std::hex << std::setw(8) << std::setfill('0') << words[idx];
for (int idx = 0; idx < dword_count; idx++) {
std::clog << " " << std::hex << std::setw(8) << std::setfill('0') << dwords[idx];
}
std::clog << std::setfill(' ') << std::endl;
#endif
}
void populateAql(void* cmd_buffer, uint32_t cmd_size,
pm4_profile::CommandWriter* cmd_writer, packet_t* aql_packet) {
void populateAql(const void* cmd_buffer, uint32_t cmd_size, pm4_profile::CommandWriter* cmd_writer,
packet_t* aql_packet) {
pm4_profile::DefaultCmdBuf ib_buffer;
cmd_writer->BuildIndirectBufferCmd(&ib_buffer, cmd_buffer, (size_t)cmd_size);
uint32_t* ib_packet = (uint32_t*)ib_buffer.Base();
populateAql(ib_packet, aql_packet);
}
populateAql((const uint32_t*)ib_buffer.Base(), aql_packet);
}
} // aql_profile
@@ -4,11 +4,6 @@
set ( CmdWriterSrcs gfx8_cmdwriter.cpp )
set ( CmdWriterSrcs ${CmdWriterSrcs} gfx9_cmdwriter.cpp )
#
# Header files include path(s).
#
include_directories ( $ENV{ROCR_INC_DIR} )
#
# Build Cmdwriter as a Static Library object
#
@@ -5,9 +5,8 @@
#define _CMDWRITER_H_
#include <vector>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
namespace pm4_profile {
@@ -471,28 +470,12 @@ class CommandWriter {
uint32_t& IndexBuffer(CmdBuf* cmdbuf, uint32_t index) { return (*cmdbuf)[index]; }
};
/// @brief Returns the Rounded value per input rounding factor
inline uint32_t RoundUp(uint32_t u, uint32_t r) { return ((u + (r - 1)) & ~(r - 1)); }
/// @brief Returns the lower 32-bits of a value
inline uint32_t Low32(uint64_t u) { return (u & 0xFFFFFFFFUL); }
/// @brief Returns the upper 32-bits of a value
inline uint32_t High32(uint64_t u) { return (u >> 32); }
/// @brief Returns the lower 32-bits of an address
inline uint32_t Ptr48Low32(const void* p) {
uintptr_t ptr = reinterpret_cast<uintptr_t>(p);
assert((ptr & 0xFFFFFFFFFF00ULL) == ptr);
return (uint32_t)((ptr & 0xFFFFFFFFFFULL) >> 8);
}
/// @brief Returns the upper 8-bits of an address
inline uint8_t Ptr48High8(const void* p) {
uintptr_t ptr = reinterpret_cast<uintptr_t>(p);
return (uint8_t)((ptr & 0xFF0000000000ULL) >> 40);
}
/// @brief Returns the lower 32-bits of an address
inline uint32_t PtrLow32(const void* p) {
return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(p));
@@ -1,7 +1,8 @@
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string.h>
#include <assert.h>
#include "gfx8_cmdwriter.h"
#include "gfxip/gfx8/gfx8_utils.h"
@@ -15,10 +16,9 @@
#define RELEASE_MEM_CACHE_POLICY_STREAM 1
#define RELEASE_MEM_CACHE_POLICY_BYPASS 2
template <class T>
static void PrintPm4Packet(const T& command, const char* name) {
#if ! defined(NDEBUG)
uint32_t * cmd = (uint32_t*)&command;
template <class T> static void PrintPm4Packet(const T& command, const char* name) {
#if !defined(NDEBUG)
uint32_t* cmd = (uint32_t*)&command;
uint32_t size = sizeof(command) / sizeof(uint32_t);
std::ostringstream oss;
oss << "'" << name << "' size(" << std::dec << size << ")";
@@ -30,8 +30,8 @@ static void PrintPm4Packet(const T& command, const char* name) {
#endif
}
#define APPEND_COMMAND_WRAPPER(cmdbuf, command) \
PrintPm4Packet(command, __FUNCTION__); \
#define APPEND_COMMAND_WRAPPER(cmdbuf, command) \
PrintPm4Packet(command, __FUNCTION__); \
AppendCommand(cmdbuf, command);
namespace pm4_profile {
@@ -164,7 +164,7 @@ Gfx8CmdWriter::Gfx8CmdWriter(bool atc_support, bool pcie_atomic_support) {
}
void Gfx8CmdWriter::BuildWaitRegMemCommand(CmdBuf* cmdbuf, bool mem_space, uint64_t wait_addr,
bool func_eq, uint32_t mask_val, uint32_t wait_val) {
bool func_eq, uint32_t mask_val, uint32_t wait_val) {
gfx8::WaitRegMemTemplate wait_cmd = wait_reg_mem_template_;
// Apply the space to which addr belongs
@@ -212,7 +212,7 @@ void Gfx8CmdWriter::BuildUpdateHostAddress(CmdBuf* cmdbuf, uint64_t* addr, int64
}
void Gfx8CmdWriter::BuildIndirectBufferCmd(CmdBuf* cmdbuf, const void* cmd_addr,
std::size_t cmd_size) {
std::size_t cmd_size) {
gfx8::LaunchTemplate launch = launch_template_;
launch.indirect_buffer.ibBaseLo = PtrLow32(cmd_addr);
@@ -223,7 +223,7 @@ void Gfx8CmdWriter::BuildIndirectBufferCmd(CmdBuf* cmdbuf, const void* cmd_addr,
}
void Gfx8CmdWriter::BuildBOPNotifyCmd(CmdBuf* cmdbuf, const void* write_addr, uint32_t write_val,
bool interrupt) {
bool interrupt) {
// Initialize the command including its header
gfx8::EndofKernelNotifyTemplate eopCmd;
memset(&eopCmd, 0, sizeof(eopCmd));
@@ -273,7 +273,7 @@ void Gfx8CmdWriter::BuildBarrierFenceCommands(CmdBuf* cmdbuf) {
#define PM4_PACKET3_CMD_SHIFT 8
#define PM4_PACKET3_COUNT_SHIFT 16
#define PACKET3(cmd, count) \
#define PACKET3(cmd, count) \
(PM4_PACKET3 | (((count)-1) << PM4_PACKET3_COUNT_SHIFT) | ((cmd) << PM4_PACKET3_CMD_SHIFT))
// Structure to store the event PM4 packet
@@ -282,7 +282,6 @@ typedef struct WriteRegPacket_ { uint32_t item[3]; } WriteRegPacket;
typedef struct WriteEventPacket_ { uint32_t item[7]; } WriteEventPacket;
void Gfx8CmdWriter::BuildWriteEventPacket(CmdBuf* cmdbuf, uint32_t event) {
PM4CMDEVENTWRITE cp_event_initiator;
cp_event_initiator.ordinal1 = PACKET3(IT_EVENT_WRITE, 1);
cp_event_initiator.ordinal2 = 0;
@@ -346,8 +345,8 @@ void Gfx8CmdWriter::BuildWriteShRegPacket(CmdBuf* cmdbuf, uint32_t addr, uint32_
}
void Gfx8CmdWriter::BuildCopyDataPacket(CmdBuf* cmdbuf, uint32_t src_sel, uint32_t src_addr_lo,
uint32_t src_addr_hi, uint32_t* dst_addr, uint32_t size,
bool wait) {
uint32_t src_addr_hi, uint32_t* dst_addr, uint32_t size,
bool wait) {
PM4CMDCOPYDATA cmd_data;
memset(&cmd_data, 0, sizeof(PM4CMDCOPYDATA));
@@ -495,9 +494,8 @@ void Gfx8CmdWriter::WriteUserData(uint32_t* dst_addr, uint32_t count, const void
}
void Gfx8CmdWriter::BuildAtomicPacket(CmdBuf* cmdbuf, AtomicType atomic_op,
volatile uint32_t* addr, uint32_t value,
uint32_t compare) {
void Gfx8CmdWriter::BuildAtomicPacket(CmdBuf* cmdbuf, AtomicType atomic_op, volatile uint32_t* addr,
uint32_t value, uint32_t compare) {
gfx8::AtomicTemplate atomic = atomic_template_;
// make sure the destination adddress is aligned
@@ -554,8 +552,7 @@ void Gfx8CmdWriter::BuildAtomicPacket(CmdBuf* cmdbuf, AtomicType atomic_op,
}
void Gfx8CmdWriter::BuildAtomicPacket64(CmdBuf* cmdbuf, AtomicType atomic_op,
volatile uint64_t* addr, uint64_t value,
uint64_t compare) {
volatile uint64_t* addr, uint64_t value, uint64_t compare) {
AtomicTemplate atomic = atomic_template_;
// make sure the destination adddress is aligned
@@ -640,7 +637,7 @@ void Gfx8CmdWriter::BuildConditionalExecute(CmdBuf* cmdbuf, uint32_t* signal, ui
}
void Gfx8CmdWriter::BuildWriteDataCommand(CmdBuf* cmdbuf, uint32_t* write_addr,
uint32_t write_value) {
uint32_t write_value) {
// Copy the initialize command packet
gfx8::WriteDataTemplate command = write_data_template_;
@@ -656,7 +653,7 @@ void Gfx8CmdWriter::BuildWriteDataCommand(CmdBuf* cmdbuf, uint32_t* write_addr,
}
void Gfx8CmdWriter::BuildWriteData64Command(CmdBuf* cmdbuf, uint64_t* write_addr,
uint64_t write_value) {
uint64_t write_value) {
// Copy the initialize command packet
gfx8::WriteData64Template command = write_data64_template_;
@@ -672,7 +669,7 @@ void Gfx8CmdWriter::BuildWriteData64Command(CmdBuf* cmdbuf, uint64_t* write_addr
}
void Gfx8CmdWriter::BuildFlushCacheCmd(CmdBuf* cmdbuf, FlushCacheOptions* options,
uint32_t* writeAddr, uint32_t writeVal) {
uint32_t* writeAddr, uint32_t writeVal) {
PM4CMDACQUIREMEM flushCmd;
memset(&flushCmd, 0, sizeof(flushCmd));
@@ -720,7 +717,7 @@ void Gfx8CmdWriter::BuildFlushCacheCmd(CmdBuf* cmdbuf, FlushCacheOptions* option
}
void Gfx8CmdWriter::BuildDmaDataPacket(CmdBuf* cmdbuf, uint32_t* srcAddr, uint32_t* dstAddr,
uint32_t copySize, bool waitForConfirm) {
uint32_t copySize, bool waitForConfirm) {
PM4CMDDMADATA cmdDmaData;
memset(&cmdDmaData, 0, sizeof(PM4CMDDMADATA));
cmdDmaData.header.u32All =
@@ -1,14 +1,14 @@
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string.h>
#include <assert.h>
#include "gfx9_cmdwriter.h"
template <class T>
static void PrintPm4Packet(const T& command, const char* name) {
#if ! defined(NDEBUG)
uint32_t * cmd = (uint32_t*)&command;
template <class T> static void PrintPm4Packet(const T& command, const char* name) {
#if !defined(NDEBUG)
uint32_t* cmd = (uint32_t*)&command;
uint32_t size = sizeof(command) / sizeof(uint32_t);
std::ostringstream oss;
oss << "'" << name << "' size(" << std::dec << size << ")";
@@ -20,8 +20,8 @@ static void PrintPm4Packet(const T& command, const char* name) {
#endif
}
#define APPEND_COMMAND_WRAPPER(cmdbuf, command) \
PrintPm4Packet(command, __FUNCTION__); \
#define APPEND_COMMAND_WRAPPER(cmdbuf, command) \
PrintPm4Packet(command, __FUNCTION__); \
AppendCommand(cmdbuf, command);
namespace pm4_profile {
@@ -1,22 +1,15 @@
#
# Source files for Rocr PerfCntr
#
set ( LIB_SRC var_data.cpp )
set ( LIB_SRC ${LIB_SRC} info_set.cpp )
set ( LIB_SRC ${LIB_SRC} parameter_set.cpp )
set ( LIB_SRC ${LIB_SRC} gpu_counter.cpp )
set ( LIB_SRC ${LIB_SRC} gpu_countergroup.cpp )
set ( LIB_SRC ${LIB_SRC} vi_blockinfo.cpp )
set ( LIB_SRC ${LIB_SRC} vi_pmu.cpp )
set ( LIB_SRC ${LIB_SRC} ai_blockinfo.cpp )
set ( LIB_SRC ${LIB_SRC} ai_pmu.cpp )
set ( LIB_SRC gfx8_perf_counter.cpp )
set ( LIB_SRC ${LIB_SRC} gfx9_perf_counter.cpp )
set ( LIB_SRC ${LIB_SRC} gfx8_block_info.cpp )
set ( LIB_SRC ${LIB_SRC} gfx9_block_info.cpp )
#
# Header files include path(s).
#
include_directories ( $ENV{ROCR_INC_DIR} )
include_directories ( ${PROJ_DIR}/commandwriter )
include_directories ( ${CORE_UTIL_DIR} )
#
# Build PerfCntr as a Static Library object
@@ -1,4 +1,4 @@
#include "vi_blockinfo.h"
#include "gfx8_block_info.h"
#include "gfxip/gfx8/si_ci_vi_merged_offset.h"
namespace pm4_profile {
@@ -6,7 +6,7 @@ namespace pm4_profile {
* Table containing CounterGroups which represent VI hardware blocks
* as defined by \ref GpuBlockInfo structure
*/
GpuBlockInfo ViPmuHwBlocks[] = {
GpuBlockInfo Gfx8HwBlocks[] = {
// Counter block CB
{"VI_CB0", kHsaViCounterBlockIdCb0, VI_MAX_NUM_SHADER_ENGINES, 2, VI_NUM_CB,
CntlMethodBySeAndInstance, 395, VI_COUNTER_NUM_PER_CB, 0, 0, true, 0, 0, false, 0, 0},
@@ -259,6 +259,8 @@ GpuBlockInfo ViPmuHwBlocks[] = {
{"", kHsaViCounterBlockIdBlocksLast, 0, 0, 0, CntlMethodNone, 0, 0, 0, 0, false, 0, 0, false, 0,
0}};
extern const uint32_t Gfx8HwBlockCount = sizeof(Gfx8HwBlocks) / sizeof(GpuBlockInfo);
/*
* The following tables contain register addresses of the SQ counter registers
*/
@@ -1,10 +1,7 @@
#ifndef _VI_BLOCKINFO_H_
#define _VI_BLOCKINFO_H_
#include <stdint.h>
#include "rocr_profiler.h"
#include "gpu_enum.h"
#include "gpu_blockinfo.h"
#include "gpu_block_info.h"
namespace pm4_profile {
@@ -187,7 +184,7 @@ typedef enum HsaViCounterBlockId {
kHsaViCounterBlockIdBlocksLast = kHsaViCounterBlockIdHwInfo
} HsaViCounterBlockId;
extern GpuBlockInfo ViPmuHwBlocks[];
extern GpuBlockInfo Gfx8HwBlocks[];
extern GpuCounterRegInfo ViSqCounterRegAddr[];
extern GpuCounterRegInfo ViCbCounterRegAddr[];
extern GpuCounterRegInfo ViDrmdmaCounterRegAddr[];
@@ -1,22 +1,21 @@
#include <string.h>
#include <iomanip>
#include "os.h"
#include <assert.h>
#include "gfxip/gfx8/si_ci_vi_merged_typedef.h"
#include "gfxip/gfx8/si_ci_vi_merged_offset.h"
#include "gfxip/gfx8/si_ci_vi_merged_enum.h"
#include "gfxip/gfx8/si_pm4defs.h"
#include "cmdwriter.h"
#include "vi_pmu.h"
#include "gpu_countergroup.h"
#include "vi_blockinfo.h"
#include "gpu_enum.h"
#include "gfx8_perf_counter.h"
#include "gfx8_block_info.h"
#include "cmdwriter.h"
using namespace std;
using namespace pm4_profile;
// A flag to indicate the current packet is for copy register value
#define MAX_REG_NUM 100
#define COPY_DATA_FLAG 0xFFFFFFFF
namespace pm4_profile {
static char errorString[][64] = {{"No error"},
@@ -27,20 +26,14 @@ static char errorString[][64] = {{"No error"},
{"countegroup error state"},
{"countegroup is not completed"}};
ViPmu::ViPmu() {
Gfx8PerfCounter::Gfx8PerfCounter() {
// Initialize the number of shader engines
num_se_ = 4;
Init();
}
void ViPmu::Init() {
void Gfx8PerfCounter::Init() {
error_code_ = 0;
info_set_ = new InfoSet();
parameter_set_ = new ParameterSet();
// Initialize pointer to stored counter block list to NULL
blk_list_ = NULL;
initCounterBlock();
// Initialize the value to use in resetting GRBM
regGRBM_GFX_INDEX grbm_gfx_index;
@@ -49,106 +42,38 @@ void ViPmu::Init() {
grbm_gfx_index.bitfields.SE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reset_grbm_ = grbm_gfx_index.u32All;
// Update state of Perf Mgmt Unit
profiler_state_ = ROCR_PMU_STATE_IDLE;
}
ViPmu::~ViPmu() {
// Remove all counter blocks
RemoveCounterBlocks();
blk_map_.clear();
delete parameter_set_;
delete info_set_;
if (blk_list_) {
free(blk_list_);
blk_list_ = NULL;
}
}
// Initializes the handle of buffer used to collect PMC data
// @param cmdBufSz Size in terms of bytes
bool ViPmu::setPmcDataBuff(uint8_t* pmcBuffer, uint32_t pmcBuffSz) {
// Update counter data buffer addr and size params
pmcDataSz_ = pmcBuffSz;
pmcData_ = (uint32_t*)pmcBuffer;
return true;
}
//
// The logic is quite simple and is as follows
//
// Issue CsPartialFlush
// Issue Cmd to stop Perf Counters
// Issue Cmd to Disable & Reset Perf Counters
//
void ViPmu::ResetCounterBlocks(pm4_profile::DefaultCmdBuf* cmdBuff,
pm4_profile::CommandWriter* cmdWriter) {
// Waits until all outstanding commands have completed
// by issing CS Partial Flush command
cmdWriter->BuildWriteWaitIdlePacket(cmdBuff);
// Program CP Perfmon Cntrl Rgstr to disable and reset counters
regCP_PERFMON_CNTL cp_perfmon_cntl;
cp_perfmon_cntl.u32All = 0;
cp_perfmon_cntl.bits.PERFMON_STATE = 0;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL__CI__VI, cp_perfmon_cntl.u32All);
}
bool ViPmu::begin(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter* cmdWriter,
bool reset_counter) {
if (profiler_state_ != ROCR_PMU_STATE_IDLE) {
error_code_ = kHsaPmuErrorCodeErrorState;
return false;
}
void Gfx8PerfCounter::begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter,
const CountersMap& countersMap) {
// Reset Grbm to its default state - broadcast
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmGRBM_GFX_INDEX__CI__VI, reset_grbm_);
// Program CP Perfmon Cntrl Rgstr to disable and reset counters
regCP_PERFMON_CNTL cp_perfmon_cntl;
cp_perfmon_cntl.u32All = 0;
cp_perfmon_cntl.bits.PERFMON_STATE = 0;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL__CI__VI, cp_perfmon_cntl.u32All);
// Collect all the program counter blocks
uint32_t reg_val[MAX_REG_NUM], reg_addr[MAX_REG_NUM], reg_num;
// Retrieve the list of blocks whose perf counters have been enabled
uint32_t blk_cnt = 0;
CounterBlock** blk_list = getAllCounterBlocks(blk_cnt);
// Iterate through the list of blocks to generate Pm4 commands to
// program corresponding perf counters of each block
for (uint32_t blkIdx = 0; blkIdx < blk_cnt; blkIdx++) {
// Retrieve the list of perf counters and their count
uint32_t counter_num;
Counter** cntr_list;
cntr_list = blk_list[blkIdx]->getEnabledCounters(counter_num);
if (counter_num == 0) {
continue;
}
// Retrieve the block Id of perf counters
void* p_data;
uint32_t block_id;
uint32_t data_size;
blk_list[blkIdx]->getInfo(GPU_BLK_INFO_ID, data_size, (void**)&p_data);
block_id = *(static_cast<uint32_t*>(p_data));
for (CountersMap::const_iterator block_it = countersMap.begin(); block_it != countersMap.end();
++block_it) {
const uint32_t block_id = block_it->first;
const CountersVec& counters = block_it->second;
const uint32_t counter_count = counters.size();
// Iterate through each enabled perf counter and building
// corresponding Pm4 commands to program the various control
// registers involved
for (uint32_t cntrIdx = 0; cntrIdx < counter_num; cntrIdx++) {
for (uint32_t ind = 0; ind < counter_count; ++ind) {
const uint32_t counter_id = counters[ind];
// Build the list of control registers to program which
// varies per perf counter block
reg_num = BuildCounterSelRegister(cntrIdx, reg_addr, reg_val, block_id, cntr_list[cntrIdx]);
uint32_t reg_addr[MAX_REG_NUM], reg_val[MAX_REG_NUM];
const uint32_t reg_num =
BuildCounterSelRegister(ind, reg_addr, reg_val, block_id, counter_id);
// Build the list of Pm4 commands that support control
// register programming
for (uint32_t regIdx = 0; regIdx < reg_num; regIdx++) {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[regIdx], reg_val[regIdx]);
for (uint32_t n = 0; n < reg_num; ++n) {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[n], reg_val[n]);
}
}
}
@@ -163,96 +88,55 @@ bool ViPmu::begin(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWrite
cmdWriter->BuildWriteShRegPacket(cmdBuff, mmCOMPUTE_PERFCOUNT_ENABLE__CI__VI,
cp_perfcount_enable.u32All);
// Start the counter list
// Reset the counter list
regCP_PERFMON_CNTL cp_perfmon_cntl;
cp_perfmon_cntl.u32All = 0;
cp_perfmon_cntl.bits.PERFMON_STATE = 0;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL__CI__VI, cp_perfmon_cntl.u32All);
// Start the counter list
cp_perfmon_cntl.bits.PERFMON_STATE = 1;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL__CI__VI, cp_perfmon_cntl.u32All);
// Issue barrier command to apply the commands to configure perfcounters
cmdWriter->BuildWriteWaitIdlePacket(cmdBuff);
profiler_state_ = ROCR_PMU_STATE_START;
return true;
}
bool ViPmu::end(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter* cmdWriter) {
if (profiler_state_ != ROCR_PMU_STATE_START) {
error_code_ = kHsaPmuErrorCodeErrorState;
return false;
}
void* p_data;
regGRBM_GFX_INDEX grbm_gfx_index;
// Issue CsPartialFlush command to wait for dispatch to complete
uint32_t Gfx8PerfCounter::end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter,
const CountersMap& countersMap, void* dataBuff) {
// Issue barrier command to wait for dispatch to complete
cmdWriter->BuildWriteWaitIdlePacket(cmdBuff);
// Build PM4 packet for starting counters
// Build PM4 packet to stop and freeze counters
regCP_PERFMON_CNTL cp_perfmon_cntl;
cp_perfmon_cntl.u32All = 0;
cp_perfmon_cntl.bits.PERFMON_STATE = 2;
cp_perfmon_cntl.bits.PERFMON_SAMPLE_ENABLE = 1;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL__CI__VI, cp_perfmon_cntl.u32All);
// Collect all the program counter blocks
uint32_t i, j, k, reg_addr[MAX_REG_NUM], reg_val[MAX_REG_NUM], reg_num, data_size;
uint32_t blk_cnt = 0;
CounterBlock** blk_list = getAllCounterBlocks(blk_cnt);
uint32_t counter_num;
Counter** cntr_list;
uint32_t total_counter_num = 0;
for (i = 0; i < blk_cnt; i++) {
// Retrieve all enabled cntr_list in each counter block
cntr_list = blk_list[i]->getEnabledCounters(counter_num);
if (!blk_list[i]->getInfo(GPU_BLK_INFO_CONTROL_METHOD, data_size, &p_data)) {
return false;
}
CntlMethod method;
method = static_cast<CntlMethod>(*(static_cast<uint32_t*>(p_data)));
// Need to read counter values from each shader engine
if (method == CntlMethodBySe || method == CntlMethodBySeAndInstance) {
counter_num = counter_num * num_se_;
}
total_counter_num += counter_num;
}
size_t cntrSize = sizeof(int32_t) * 2 * total_counter_num;
if (cntrSize > pmcDataSz_) {
return false;
}
// Reset Grbm to its default state - broadcast
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmGRBM_GFX_INDEX__CI__VI, reset_grbm_);
// Create PM4 packet to read counter values
total_counter_num = 0;
for (i = 0; i < blk_cnt; i++) {
// Retrieve all enabled cntr_list in each counter block
cntr_list = blk_list[i]->getEnabledCounters(counter_num);
if (counter_num > 0) {
uint32_t block_id;
uint32_t data_size;
if (!blk_list[i]->getInfo(GPU_BLK_INFO_ID, data_size, (void**)&p_data)) {
return false;
}
block_id = *(static_cast<uint32_t*>(p_data));
// Iterate through the list of blocks to create PM4 packets to read counter values
uint32_t total_counter_num = 0;
for (CountersMap::const_iterator block_it = countersMap.begin(); block_it != countersMap.end();
++block_it) {
const uint32_t block_id = block_it->first;
const uint32_t counter_count = block_it->second.size();
for (j = 0; j < counter_num; j++) {
// retrieve the registers to be set
reg_num = BuildCounterReadRegisters(j, block_id, reg_addr, reg_val);
for (k = 0; k < reg_num; k++) {
if (reg_val[k] == COPY_DATA_FLAG) {
cmdWriter->BuildCopyDataPacket(cmdBuff, COPY_DATA_SEL_REG, reg_addr[k], 0,
pmcData_ + total_counter_num, COPY_DATA_SEL_COUNT_1DW,
false);
total_counter_num++;
} else {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[k], reg_val[k]);
}
for (uint32_t ind = 0; ind < counter_count; ++ind) {
// retrieve the registers to be set
uint32_t reg_addr[MAX_REG_NUM], reg_val[MAX_REG_NUM];
const uint32_t reg_num = BuildCounterReadRegisters(ind, block_id, reg_addr, reg_val);
for (uint32_t n = 0; n < reg_num; n++) {
if (reg_val[n] == COPY_DATA_FLAG) {
cmdWriter->BuildCopyDataPacket(cmdBuff, COPY_DATA_SEL_REG, reg_addr[n], 0,
((uint32_t*)dataBuff) + total_counter_num,
COPY_DATA_SEL_COUNT_1DW, false);
total_counter_num++;
} else {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[n], reg_val[n]);
}
}
}
@@ -261,138 +145,21 @@ bool ViPmu::end(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter*
// Reset Grbm to its default state - broadcast
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmGRBM_GFX_INDEX__CI__VI, reset_grbm_);
profiler_state_ = ROCR_PMU_STATE_STOP;
return true;
return total_counter_num * sizeof(uint32_t);
}
bool ViPmu::initCounterBlock() {
for (int i = 0; !(std::string(ViPmuHwBlocks[i].blockName).empty()); i++) {
// Override the value of max number of shader engines
ViPmuHwBlocks[i].maxShaderEngineCount = num_se_;
int Gfx8PerfCounter::getLastError() { return error_code_; }
// Instantiate a perf counter block and its properties
GpuCounterBlock* cntr_blk = new GpuCounterBlock();
if (!cntr_blk) {
blk_map_.clear();
return false;
}
cntr_blk->setInfo(GPU_BLK_INFO_BLOCK_NAME, GPU_BLOCK_NAME_SIZE,
(void*)ViPmuHwBlocks[i].blockName);
cntr_blk->setInfo(GPU_BLK_INFO_ID, sizeof(uint32_t), (void*)&ViPmuHwBlocks[i].counterGroupId);
cntr_blk->setInfo(GPU_BLK_INFO_MAX_SHADER_ENGINE_COUNT, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].maxShaderEngineCount));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_SHADER_ARRAY_COUNT, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].maxShaderArrayCount));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_INSTANCE_COUNT, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].maxInstanceCount));
cntr_blk->setInfo(GPU_BLK_INFO_CONTROL_METHOD, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].method));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_EVENT_ID, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].maxEventId));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_SIMULTANEOUS_COUNTERS, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].maxSimultaneousCounters));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_STREAMING_COUNTERS, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].maxStreamingCounters));
cntr_blk->setInfo(GPU_BLK_INFO_SHARED_HW_COUNTERS, sizeof(uint32_t),
(void*)&(ViPmuHwBlocks[i].sharedHWCounters));
cntr_blk->setInfo(GPU_BLK_INFO_HAS_FILTERS, sizeof(bool),
(void*)&(ViPmuHwBlocks[i].hasFilters));
// TODO: Need to fill in the Threadtrace stuff here
HsaViCounterBlockId blk_id;
blk_id = static_cast<HsaViCounterBlockId>(ViPmuHwBlocks[i].counterGroupId);
blk_map_.insert(ViCounterBlockMap::value_type(blk_id, cntr_blk));
}
// Initiate the PMU state and error code
error_code_ = 0;
profiler_state_ = ROCR_PMU_STATE_IDLE;
return true;
}
int ViPmu::getLastError() { return error_code_; }
std::string ViPmu::getErrorString(int error) {
if ((error >= 0) && (error < kHsaPmuErrorCodeMax)) {
std::string Gfx8PerfCounter::getErrorString(int error) {
if ((error >= 0) && (error < kErrorCodeMax)) {
std::string err_string(errorString[error]);
return err_string;
}
return string("Error input code!");
}
bool ViPmu::getParameter(uint32_t param, uint32_t& retSize, void** ppData) {
return parameter_set_->getParameter(param, retSize, ppData);
}
bool ViPmu::setParameter(uint32_t param, uint32_t paramSize, const void* p_data) {
return parameter_set_->setParameter(param, paramSize, p_data);
}
bool ViPmu::getInfo(uint32_t info, uint32_t& retSize, void** ppData) {
return info_set_->getInfo(info, retSize, ppData);
}
pm4_profile::CounterBlock* ViPmu::getCounterBlockById(uint32_t id) {
HsaViCounterBlockId block_id = static_cast<HsaViCounterBlockId>(id);
// Carrizo has only 8 instances of TA, TD, TCP Perf Blocks
/*
if (asic_ == HsaAmdDeviceAsicTypeCZ) {
if ( ((id >= kHsaViCounterBlockIdTa8) && (id <= kHsaViCounterBlockIdTa15)) ||
((id >= kHsaViCounterBlockIdTd8) && (id <= kHsaViCounterBlockIdTd15)) ||
((id >= kHsaViCounterBlockIdTcp8) && (id <= kHsaViCounterBlockIdTcp15))) {
return NULL;
}
}
*/
return blk_map_[block_id];
}
pm4_profile::CounterBlock** ViPmu::getAllCounterBlocks(uint32_t& num_blocks) {
size_t block_size = blk_map_.size();
if (block_size <= 0) {
error_code_ = kHsaPmuErrorCodeNoCounterBlock;
return NULL;
}
if (blk_list_) {
free(blk_list_);
blk_list_ = NULL;
}
blk_list_size_ = (uint32_t)(sizeof(GpuCounterBlock*) * block_size);
blk_list_size_ = ((blk_list_size_ % 4096) != 0) ? 4096 : blk_list_size_;
blk_list_ = (CounterBlock**)malloc(blk_list_size_);
if (blk_list_ == NULL) {
return NULL;
}
ViCounterBlockMap::iterator it;
uint32_t blk_cnt = 0;
for (it = blk_map_.begin(); it != blk_map_.end(); it++) {
blk_list_[blk_cnt] = it->second;
blk_cnt++;
}
num_blocks = blk_cnt;
return blk_list_;
}
uint32_t ViPmu::ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx8PerfCounter::ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -416,8 +183,8 @@ uint32_t ViPmu::ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t*
return regIdx;
}
uint32_t ViPmu::ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx8PerfCounter::ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -440,8 +207,8 @@ uint32_t ViPmu::ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* r
return regIdx;
}
uint32_t ViPmu::ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx8PerfCounter::ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -465,8 +232,8 @@ uint32_t ViPmu::ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t*
return regIdx;
}
uint32_t ViPmu::ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx8PerfCounter::ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -489,8 +256,8 @@ uint32_t ViPmu::ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t*
return regIdx;
}
uint32_t ViPmu::ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx8PerfCounter::ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -514,8 +281,8 @@ uint32_t ViPmu::ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* r
return regIdx;
}
uint32_t ViPmu::ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx8PerfCounter::ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t regIdx = 0;
// Program the SQ Counter Select Register
@@ -573,22 +340,13 @@ uint32_t ViPmu::ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* r
return regIdx;
}
uint32_t ViPmu::BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, pm4_profile::Counter* blkCntr) {
void* p_data;
uint32_t data_size;
uint32_t blkCntrIdx;
uint32_t instance_index;
regGRBM_GFX_INDEX grbm_gfx_index;
// Get the blkCntr selection value
if (!blkCntr->getParameter(HSA_EXT_TOOLS_COUNTER_PARAMETER_EVENT_INDEX, data_size,
(void**)&p_data)) {
return 0;
}
blkCntrIdx = *(static_cast<uint32_t*>(p_data));
uint32_t Gfx8PerfCounter::BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr,
uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx) {
uint32_t instance_index = 0;
regGRBM_GFX_INDEX grbm_gfx_index = {0};
uint32_t regIdx = 0;
switch (blkId) {
// Program counters belonging to SQ block
case kHsaViCounterBlockIdSq:
@@ -1011,8 +769,8 @@ uint32_t ViPmu::BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uin
return regIdx;
}
uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id, uint32_t* reg_addr,
uint32_t* reg_val) {
uint32_t Gfx8PerfCounter::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
uint32_t* reg_addr, uint32_t* reg_val) {
uint32_t ii;
uint32_t reg_num = 0;
uint32_t instance_index;
@@ -1031,6 +789,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1056,6 +815,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_INDEX = instance_index;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1096,6 +856,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_INDEX = instance_index;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1147,6 +908,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1168,6 +930,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1189,6 +952,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1210,6 +974,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1247,6 +1012,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_INDEX = instance_index;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1269,6 +1035,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_INDEX = instance_index;
grbm_gfx_index.bitfields.SE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1377,6 +1144,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_INDEX = instance_index;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1413,6 +1181,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1434,6 +1203,7 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
grbm_gfx_index.bitfields.INSTANCE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SE_INDEX = ii;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reg_addr[reg_num] = mmGRBM_GFX_INDEX__CI__VI;
reg_val[reg_num] = grbm_gfx_index.u32All;
reg_num++;
@@ -1554,16 +1324,4 @@ uint32_t ViPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
return reg_num;
}
hsa_status_t ViPmu::RemoveCounterBlocks() {
ViCounterBlockMap::iterator it = blk_map_.begin();
ViCounterBlockMap::iterator block_end = blk_map_.end();
for (; it != block_end; it++) {
delete it->second;
}
return HSA_STATUS_SUCCESS;
}
} /* namespace */
@@ -0,0 +1,77 @@
#ifndef _VI_PMU_H_
#define _VI_PMU_H_
#include <stdint.h>
#include "perf_counter.h"
namespace pm4_profile {
class CommandWriter;
// This class implement the VI PMU. It is responsible for setting up
// CounterGroups to represent each VI hardware block which exposes performance
// counters.
class Gfx8PerfCounter : public pm4_profile::Pmu {
public:
Gfx8PerfCounter();
// Returns number of shader engines per block
// for the blocks featured shader engines instancing
uint32_t getNumSe() { return num_se_; }
int getLastError();
std::string getErrorString(int error);
void begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter, const CountersMap& countersMap);
uint32_t end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter, const CountersMap& countersMap,
void* dataBuff);
private:
void Init();
// Program SQ block related counters
uint32_t ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TA block related counters
uint32_t ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TCA block related counters
uint32_t ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TCC block related counters
uint32_t ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TCP block related counters
uint32_t ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TD block related counters
uint32_t ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Build counter selection register, return how many registers are built
uint32_t BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx);
// Build counter selection register, return how many registers are built
uint32_t BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id, uint32_t* reg_addr,
uint32_t* reg_val);
private:
int error_code_;
// Indicates the number of Shader Engines Present
uint32_t num_se_;
// Used to reset GRBM to its default state
uint32_t reset_grbm_;
};
}
#endif // _VI_PMU_H_
@@ -1,4 +1,4 @@
#include "ai_blockinfo.h"
#include "gfx9_block_info.h"
#include "gfxip/gfx9/gfx9_offset.h"
#include "gfxip/gfx9/gfx9_typedef.h"
@@ -7,7 +7,7 @@ namespace pm4_profile {
* Table containing CounterGroups which represent AI hardware blocks
* as defined by \ref GpuBlockInfo structure
*/
GpuBlockInfo AiPmuHwBlocks[] = {
GpuBlockInfo Gfx9HwBlocks[] = {
// Counter block CB
{"AI_CB0", kHsaAiCounterBlockIdCb0, AI_MAX_NUM_SHADER_ENGINES, 2, AI_NUM_CB,
CntlMethodBySeAndInstance, 395, AI_COUNTER_NUM_PER_CB, 0, 0, true, 0, 0, false, 0, 0},
@@ -270,6 +270,8 @@ GpuBlockInfo AiPmuHwBlocks[] = {
{"", kHsaAiCounterBlockIdBlocksLast, 0, 0, 0, CntlMethodNone, 0, 0, 0, 0, false, 0, 0, false, 0,
0}};
extern const uint32_t Gfx9HwBlockCount = sizeof(Gfx9HwBlocks) / sizeof(GpuBlockInfo);
/*
* The following tables contain register addresses of the SQ counter registers
*/
@@ -1,10 +1,7 @@
#ifndef _AI_BLOCKINFO_H_
#define _AI_BLOCKINFO_H_
#include <stdint.h>
#include "rocr_profiler.h"
#include "gpu_enum.h"
#include "gpu_blockinfo.h"
#include "gpu_block_info.h"
namespace pm4_profile {
@@ -208,7 +205,7 @@ typedef enum HsaAiCounterBlockId {
kHsaAiCounterBlockIdBlocksLast = kHsaAiCounterBlockIdHwInfo
} HsaAiCounterBlockId;
extern GpuBlockInfo AiPmuHwBlocks[];
extern GpuBlockInfo Gfx9HwBlocks[];
extern GpuCounterRegInfo AiSqCounterRegAddr[];
extern GpuCounterRegInfo AiCbCounterRegAddr[];
extern GpuCounterRegInfo AiDrmdmaCounterRegAddr[];
@@ -1,30 +1,21 @@
#include "os.h"
#include <assert.h>
#include "gfxip/gfx9/gfx9_registers.h"
#include "gfxip/gfx9/gfx9_typedef.h"
#include "gfxip/gfx9/gfx9_offset.h"
#include "gfxip/gfx9/gfx9_pm4defs.h"
#include "gfx9_perf_counter.h"
#include "gfx9_block_info.h"
#include "cmdwriter.h"
#include "ai_pmu.h"
#include "gpu_countergroup.h"
#include "ai_blockinfo.h"
#include "gpu_enum.h"
#include <string.h>
#include <iomanip>
#include <iostream>
using namespace std;
using namespace pm4_profile;
using namespace pm4_profile::gfx9;
// A flag to indicate the current packet is for copy register value
#define MAX_REG_NUM (100)
#define COPY_DATA_FLAG (0xFFFFFFFF)
#define COPY_DATA_SEL_REG (0x00) ///< Mem-mapped register
#define COPY_DATA_SEL_COUNT_1DW (0x00) ///< Copy 1 word (32 bits)
#define COPY_DATA_SEL_COUNT_2DW (0x01) ///< Copy 2 words (64 bits)
#define MAX_REG_NUM 100
#define COPY_DATA_FLAG 0xFFFFFFFF
namespace pm4_profile {
@@ -36,20 +27,14 @@ static char errorString[][64] = {{"No error"},
{"countegroup error state"},
{"countegroup is not completed"}};
AiPmu::AiPmu() {
Gfx9PerfCounter::Gfx9PerfCounter() {
// Initialize the number of shader engines
num_se_ = 4;
Init();
}
void AiPmu::Init() {
void Gfx9PerfCounter::Init() {
error_code_ = 0;
info_set_ = new InfoSet();
parameter_set_ = new ParameterSet();
// Initialize pointer to stored counter block list to NULL
blk_list_ = NULL;
initCounterBlock();
// Initialize the value to use in resetting GRBM
regGRBM_GFX_INDEX grbm_gfx_index;
@@ -58,60 +43,10 @@ void AiPmu::Init() {
grbm_gfx_index.bitfields.SE_BROADCAST_WRITES = 1;
grbm_gfx_index.bitfields.SH_BROADCAST_WRITES = 1;
reset_grbm_ = grbm_gfx_index.u32All;
// Update state of Perf Mgmt Unit
profiler_state_ = ROCR_PMU_STATE_IDLE;
}
AiPmu::~AiPmu() {
// Remove all counter blocks
RemoveCounterBlocks();
blk_map_.clear();
delete parameter_set_;
delete info_set_;
if (blk_list_) {
free(blk_list_);
blk_list_ = NULL;
}
}
// Initializes the handle of buffer used to collect PMC data
// @param cmdBufSz Size in terms of bytes
bool AiPmu::setPmcDataBuff(uint8_t* pmcBuffer, uint32_t pmcBuffSz) {
// Update counter data buffer addr and size params
pmcDataSz_ = pmcBuffSz;
pmcData_ = (uint32_t*)pmcBuffer;
return true;
}
//
// The logic is quite simple and is as follows
//
// Issue CsPartialFlush
// Issue Cmd to stop Perf Counters
// Issue Cmd to Disable & Reset Perf Counters
//
void AiPmu::ResetCounterBlocks(pm4_profile::DefaultCmdBuf* cmdBuff,
pm4_profile::CommandWriter* cmdWriter) {
// Waits until all outstanding commands have completed
// by issing CS Partial Flush command
cmdWriter->BuildWriteWaitIdlePacket(cmdBuff);
// Program CP Perfmon Cntrl Rgstr to disable and reset counters
regCP_PERFMON_CNTL cp_perfmon_cntl;
cp_perfmon_cntl.u32All = 0;
cp_perfmon_cntl.bits.PERFMON_STATE = 0;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL, cp_perfmon_cntl.u32All);
}
bool AiPmu::begin(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter* cmdWriter,
bool reset_counter) {
if (profiler_state_ != ROCR_PMU_STATE_IDLE) {
error_code_ = kHsaPmuErrorCodeErrorState;
return false;
}
void Gfx9PerfCounter::begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter,
const CountersMap& countersMap) {
// Reset Grbm to its default state - broadcast
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmGRBM_GFX_INDEX, reset_grbm_);
@@ -119,43 +54,31 @@ bool AiPmu::begin(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWrite
// On Vega this is needed to collect Perf Cntrs
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmRLC_PERFMON_CLK_CNTL, 1);
// Collect all the program counter blocks
uint32_t reg_val[MAX_REG_NUM], reg_addr[MAX_REG_NUM], reg_num;
// Retrieve the list of blocks whose perf counters have been enabled
uint32_t blk_cnt = 0;
CounterBlock** blk_list = getAllCounterBlocks(blk_cnt);
// Iterate through the list of blocks to generate Pm4 commands to
// program corresponding perf counters of each block
for (uint32_t blkIdx = 0; blkIdx < blk_cnt; blkIdx++) {
// Retrieve the list of perf counters and their count
uint32_t counter_num;
Counter** cntr_list;
cntr_list = blk_list[blkIdx]->getEnabledCounters(counter_num);
if (counter_num == 0) {
continue;
}
// Retrieve the block Id of perf counters
void* p_data;
uint32_t block_id;
uint32_t data_size;
blk_list[blkIdx]->getInfo(GPU_BLK_INFO_ID, data_size, (void**)&p_data);
block_id = *(static_cast<uint32_t*>(p_data));
for (CountersMap::const_iterator block_it = countersMap.begin(); block_it != countersMap.end();
++block_it) {
const uint32_t block_id = block_it->first;
const CountersVec& counters = block_it->second;
const uint32_t counter_count = counters.size();
// Iterate through each enabled perf counter and building
// corresponding Pm4 commands to program the various control
// registers involved
for (uint32_t cntrIdx = 0; cntrIdx < counter_num; cntrIdx++) {
for (uint32_t ind = 0; ind < counter_count; ++ind) {
const uint32_t counter_id = counters[ind];
// Build the list of control registers to program which
// varies per perf counter block
reg_num = BuildCounterSelRegister(cntrIdx, reg_addr, reg_val, block_id, cntr_list[cntrIdx]);
uint32_t reg_addr[MAX_REG_NUM], reg_val[MAX_REG_NUM];
const uint32_t reg_num =
BuildCounterSelRegister(ind, reg_addr, reg_val, block_id, counter_id);
// Build the list of Pm4 commands that support control
// register programming
for (uint32_t regIdx = 0; regIdx < reg_num; regIdx++) {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[regIdx], reg_val[regIdx]);
for (uint32_t n = 0; n < reg_num; ++n) {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[n], reg_val[n]);
}
}
}
@@ -179,91 +102,45 @@ bool AiPmu::begin(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWrite
cp_perfmon_cntl.bits.PERFMON_STATE = 1;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL, cp_perfmon_cntl.u32All);
// Issue barrier command to apply the commands to configure perfcounters
cmdWriter->BuildWriteWaitIdlePacket(cmdBuff);
profiler_state_ = ROCR_PMU_STATE_START;
return true;
}
bool AiPmu::end(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter* cmdWriter) {
if (profiler_state_ != ROCR_PMU_STATE_START) {
error_code_ = kHsaPmuErrorCodeErrorState;
return false;
}
void* p_data;
regGRBM_GFX_INDEX grbm_gfx_index;
// Issue CsPartialFlush command to wait for dispatch to complete
uint32_t Gfx9PerfCounter::end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter,
const CountersMap& countersMap, void* dataBuff) {
// Issue barrier command to wait for dispatch to complete
cmdWriter->BuildWriteWaitIdlePacket(cmdBuff);
// Build PM4 packet for starting counters
// Build PM4 packet to stop and freeze counters
regCP_PERFMON_CNTL cp_perfmon_cntl;
cp_perfmon_cntl.u32All = 0;
cp_perfmon_cntl.bits.PERFMON_STATE = 2;
cp_perfmon_cntl.bits.PERFMON_SAMPLE_ENABLE = 1;
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmCP_PERFMON_CNTL, cp_perfmon_cntl.u32All);
// Collect all the program counter blocks
uint32_t i, j, k, reg_addr[MAX_REG_NUM], reg_val[MAX_REG_NUM], reg_num, data_size;
uint32_t blk_cnt = 0;
CounterBlock** blk_list = getAllCounterBlocks(blk_cnt);
uint32_t counter_num;
Counter** cntr_list;
uint32_t total_counter_num = 0;
for (i = 0; i < blk_cnt; i++) {
// Retrieve all enabled cntr_list in each counter block
cntr_list = blk_list[i]->getEnabledCounters(counter_num);
if (!blk_list[i]->getInfo(GPU_BLK_INFO_CONTROL_METHOD, data_size, &p_data)) {
return false;
}
CntlMethod method;
method = static_cast<CntlMethod>(*(static_cast<uint32_t*>(p_data)));
// Need to read counter values from each shader engine
if (method == CntlMethodBySe || method == CntlMethodBySeAndInstance) {
counter_num = counter_num * num_se_;
}
total_counter_num += counter_num;
}
size_t cntrSize = sizeof(int32_t) * 2 * total_counter_num;
if (cntrSize > pmcDataSz_) {
return false;
}
// Reset Grbm to its default state - broadcast
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmGRBM_GFX_INDEX, reset_grbm_);
// Create PM4 packet to read counter values
total_counter_num = 0;
for (i = 0; i < blk_cnt; i++) {
// Retrieve all enabled cntr_list in each counter block
cntr_list = blk_list[i]->getEnabledCounters(counter_num);
if (counter_num > 0) {
uint32_t block_id;
uint32_t data_size;
if (!blk_list[i]->getInfo(GPU_BLK_INFO_ID, data_size, (void**)&p_data)) {
return false;
}
block_id = *(static_cast<uint32_t*>(p_data));
// Iterate through the list of blocks to create PM4 packets to read counter values
uint32_t total_counter_num = 0;
for (CountersMap::const_iterator block_it = countersMap.begin(); block_it != countersMap.end();
++block_it) {
const uint32_t block_id = block_it->first;
const uint32_t counter_count = block_it->second.size();
for (j = 0; j < counter_num; j++) {
// retrieve the registers to be set
reg_num = BuildCounterReadRegisters(j, block_id, reg_addr, reg_val);
for (k = 0; k < reg_num; k++) {
if (reg_val[k] == COPY_DATA_FLAG) {
cmdWriter->BuildCopyDataPacket(cmdBuff, COPY_DATA_SEL_REG, reg_addr[k], 0,
pmcData_ + total_counter_num, COPY_DATA_SEL_COUNT_1DW,
false);
total_counter_num++;
} else {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[k], reg_val[k]);
}
for (uint32_t ind = 0; ind < counter_count; ++ind) {
// retrieve the registers to be set
uint32_t reg_addr[MAX_REG_NUM], reg_val[MAX_REG_NUM];
const uint32_t reg_num = BuildCounterReadRegisters(ind, block_id, reg_addr, reg_val);
for (uint32_t n = 0; n < reg_num; n++) {
if (reg_val[n] == COPY_DATA_FLAG) {
cmdWriter->BuildCopyDataPacket(cmdBuff, COPY_DATA_SEL_REG, reg_addr[n], 0,
((uint32_t*)dataBuff) + total_counter_num,
COPY_DATA_SEL_COUNT_1DW, false);
total_counter_num++;
} else {
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, reg_addr[n], reg_val[n]);
}
}
}
@@ -276,127 +153,21 @@ bool AiPmu::end(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter*
// was disabled during Perf Cntrs collection session
cmdWriter->BuildWriteUConfigRegPacket(cmdBuff, mmRLC_PERFMON_CLK_CNTL, 0);
profiler_state_ = ROCR_PMU_STATE_STOP;
return true;
return total_counter_num * sizeof(uint32_t);
}
bool AiPmu::initCounterBlock() {
for (int i = 0; !(std::string(AiPmuHwBlocks[i].blockName).empty()); i++) {
// Override the value of max number of shader engines
AiPmuHwBlocks[i].maxShaderEngineCount = num_se_;
int Gfx9PerfCounter::getLastError() { return error_code_; }
// Instantiate a perf counter block and its properties
GpuCounterBlock* cntr_blk = new GpuCounterBlock();
if (!cntr_blk) {
blk_map_.clear();
return false;
}
cntr_blk->setInfo(GPU_BLK_INFO_BLOCK_NAME, GPU_BLOCK_NAME_SIZE,
(void*)AiPmuHwBlocks[i].blockName);
cntr_blk->setInfo(GPU_BLK_INFO_ID, sizeof(uint32_t), (void*)&AiPmuHwBlocks[i].counterGroupId);
cntr_blk->setInfo(GPU_BLK_INFO_MAX_SHADER_ENGINE_COUNT, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].maxShaderEngineCount));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_SHADER_ARRAY_COUNT, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].maxShaderArrayCount));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_INSTANCE_COUNT, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].maxInstanceCount));
cntr_blk->setInfo(GPU_BLK_INFO_CONTROL_METHOD, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].method));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_EVENT_ID, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].maxEventId));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_SIMULTANEOUS_COUNTERS, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].maxSimultaneousCounters));
cntr_blk->setInfo(GPU_BLK_INFO_MAX_STREAMING_COUNTERS, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].maxStreamingCounters));
cntr_blk->setInfo(GPU_BLK_INFO_SHARED_HW_COUNTERS, sizeof(uint32_t),
(void*)&(AiPmuHwBlocks[i].sharedHWCounters));
cntr_blk->setInfo(GPU_BLK_INFO_HAS_FILTERS, sizeof(bool),
(void*)&(AiPmuHwBlocks[i].hasFilters));
// TODO: Need to fill in the Threadtrace stuff here
HsaAiCounterBlockId blk_id;
blk_id = static_cast<HsaAiCounterBlockId>(AiPmuHwBlocks[i].counterGroupId);
blk_map_.insert(AiCounterBlockMap::value_type(blk_id, cntr_blk));
}
// Initiate the PMU state and error code
error_code_ = 0;
profiler_state_ = ROCR_PMU_STATE_IDLE;
return true;
}
int AiPmu::getLastError() { return error_code_; }
std::string AiPmu::getErrorString(int error) {
if ((error >= 0) && (error < kHsaPmuErrorCodeMax)) {
std::string Gfx9PerfCounter::getErrorString(int error) {
if ((error >= 0) && (error < kErrorCodeMax)) {
std::string err_string(errorString[error]);
return err_string;
}
return string("Error input code!");
}
bool AiPmu::getParameter(uint32_t param, uint32_t& retSize, void** ppData) {
return parameter_set_->getParameter(param, retSize, ppData);
}
bool AiPmu::setParameter(uint32_t param, uint32_t paramSize, const void* p_data) {
return parameter_set_->setParameter(param, paramSize, p_data);
}
bool AiPmu::getInfo(uint32_t info, uint32_t& retSize, void** ppData) {
return info_set_->getInfo(info, retSize, ppData);
}
pm4_profile::CounterBlock* AiPmu::getCounterBlockById(uint32_t id) {
HsaAiCounterBlockId block_id = static_cast<HsaAiCounterBlockId>(id);
return blk_map_[block_id];
}
pm4_profile::CounterBlock** AiPmu::getAllCounterBlocks(uint32_t& num_blocks) {
size_t block_size = blk_map_.size();
if (block_size <= 0) {
error_code_ = kHsaPmuErrorCodeNoCounterBlock;
return NULL;
}
if (blk_list_) {
free(blk_list_);
blk_list_ = NULL;
}
blk_list_size_ = (uint32_t)(sizeof(GpuCounterBlock*) * block_size);
blk_list_size_ = ((blk_list_size_ % 4096) != 0) ? 4096 : blk_list_size_;
blk_list_ = (CounterBlock**)malloc(blk_list_size_);
if (blk_list_ == NULL) {
return NULL;
}
AiCounterBlockMap::iterator it;
uint32_t blk_cnt = 0;
for (it = blk_map_.begin(); it != blk_map_.end(); it++) {
blk_list_[blk_cnt] = it->second;
blk_cnt++;
}
num_blocks = blk_cnt;
return blk_list_;
}
uint32_t AiPmu::ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx9PerfCounter::ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -420,8 +191,8 @@ uint32_t AiPmu::ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t*
return regIdx;
}
uint32_t AiPmu::ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx9PerfCounter::ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -444,8 +215,8 @@ uint32_t AiPmu::ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* r
return regIdx;
}
uint32_t AiPmu::ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx9PerfCounter::ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -469,8 +240,8 @@ uint32_t AiPmu::ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t*
return regIdx;
}
uint32_t AiPmu::ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx9PerfCounter::ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -493,8 +264,8 @@ uint32_t AiPmu::ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t*
return regIdx;
}
uint32_t AiPmu::ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx9PerfCounter::ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
regGRBM_GFX_INDEX grbm_gfx_index;
grbm_gfx_index.u32All = 0;
@@ -518,8 +289,8 @@ uint32_t AiPmu::ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* r
return regIdx;
}
uint32_t AiPmu::ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t Gfx9PerfCounter::ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, uint32_t blkCntrIdx) {
uint32_t regIdx = 0;
// Program the SQ Counter Select Register
@@ -571,22 +342,13 @@ uint32_t AiPmu::ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* r
return regIdx;
}
uint32_t AiPmu::BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, pm4_profile::Counter* blkCntr) {
void* p_data;
uint32_t data_size;
uint32_t blkCntrIdx;
uint32_t instance_index;
regGRBM_GFX_INDEX grbm_gfx_index;
// Get the blkCntr selection value
if (!blkCntr->getParameter(HSA_EXT_TOOLS_COUNTER_PARAMETER_EVENT_INDEX, data_size,
(void**)&p_data)) {
return 0;
}
blkCntrIdx = *(static_cast<uint32_t*>(p_data));
uint32_t Gfx9PerfCounter::BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr,
uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx) {
uint32_t instance_index = 0;
regGRBM_GFX_INDEX grbm_gfx_index = {0};
uint32_t regIdx = 0;
switch (blkId) {
// Program counters belonging to SQ block
case kHsaAiCounterBlockIdSq:
@@ -1019,8 +781,8 @@ uint32_t AiPmu::BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uin
return regIdx;
}
uint32_t AiPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id, uint32_t* reg_addr,
uint32_t* reg_val) {
uint32_t Gfx9PerfCounter::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
uint32_t* reg_addr, uint32_t* reg_val) {
uint32_t ii;
uint32_t reg_num = 0;
uint32_t instance_index;
@@ -1586,16 +1348,4 @@ uint32_t AiPmu::BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id,
return reg_num;
}
hsa_status_t AiPmu::RemoveCounterBlocks() {
AiCounterBlockMap::iterator it = blk_map_.begin();
AiCounterBlockMap::iterator block_end = blk_map_.end();
for (; it != block_end; it++) {
delete it->second;
}
return HSA_STATUS_SUCCESS;
}
} /* namespace */
@@ -1,78 +1,36 @@
#ifndef _AI_PMU_H_
#define _AI_PMU_H_
#include "hsa.h"
#include "cmdwriter.h"
#include "hsa_perf.h"
#include "info_set.h"
#include "parameter_set.h"
#include "ai_blockinfo.h"
#include "rocr_profiler.h"
#include <stdlib.h>
#include <stdint.h>
#include <map>
#include "perf_counter.h"
namespace pm4_profile {
typedef std::map<HsaAiCounterBlockId, pm4_profile::CounterBlock*> AiCounterBlockMap;
class CommandWriter;
// This class implement the AI PMU. It is responsible for setting up
// CounterGroups to represent each AI hardware block which exposes performance
// counters.
class AiPmu : public pm4_profile::Pmu {
class Gfx9PerfCounter : public pm4_profile::Pmu {
public:
AiPmu();
~AiPmu();
Gfx9PerfCounter();
// Returns number of shader engines per block
// for the blocks featured shader engines instancing
uint32_t getNumSe() { return num_se_; }
// Initializes the handle of buffer used to collect PMC data
bool setPmcDataBuff(uint8_t* pmcBuffer, uint32_t pmcBuffSz);
int getLastError();
std::string getErrorString(int error);
virtual bool begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter, bool reset = true);
void begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter, const CountersMap& countersMap);
virtual bool end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter);
// IPMU inherits the IParameterSet and IInfoSetso we implement it
// through composition and function forwarding
bool getParameter(uint32_t param, uint32_t& ret_size, void** pp_data);
bool setParameter(uint32_t param, uint32_t param_size, const void* p_data);
bool getInfo(uint32_t info, uint32_t& ret_size, void** pp_data);
pm4_profile::CounterBlock* getCounterBlockById(uint32_t id);
rocr_pmu_state_t getCurrentState() { return profiler_state_; }
pm4_profile::CounterBlock** getAllCounterBlocks(uint32_t& num_groups);
uint32_t end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter, const CountersMap& countersMap,
void* dataBuff);
private:
// Addr of Counter Data Buffer
uint32_t* pmcData_;
// Size of Counter Data Buffer
uint32_t pmcDataSz_;
void Init();
bool initCounterBlock();
bool isResultReady();
// Clear CounterBlockMap
void clearCounterBlockMap();
// Reset SQ and CB counters
void ResetCounterBlocks(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter);
// Program SQ block related counters
uint32_t ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
@@ -99,33 +57,15 @@ class AiPmu : public pm4_profile::Pmu {
// Build counter selection register, return how many registers are built
uint32_t BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, pm4_profile::Counter* blkCntr);
uint32_t blkId, uint32_t blkCntrIdx);
// Build counter selection register, return how many registers are built
uint32_t BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id, uint32_t* reg_addr,
uint32_t* reg_val);
private:
// Delete counter blocks in the PMU
hsa_status_t RemoveCounterBlocks();
private:
// This contains the available counter groups.
AiCounterBlockMap blk_map_;
// This stores the current profiling state.
rocr_pmu_state_t profiler_state_;
pm4_profile::ParameterSet* parameter_set_;
pm4_profile::InfoSet* info_set_;
int error_code_;
// Pointer used to store counter block list internally
uint32_t blk_list_size_;
pm4_profile::CounterBlock** blk_list_;
// Indicates the number of Shader Engines Present
uint32_t num_se_;
@@ -1,9 +1,6 @@
#ifndef _GPU_BLOCKINFO_H_
#define _GPU_BLOCKINFO_H_
#include "rocr_profiler.h"
#include "gpu_enum.h"
#include <stdint.h>
namespace pm4_profile {
@@ -1,73 +0,0 @@
#include "gpu_counter.h"
using namespace pm4_profile;
namespace pm4_profile {
static char error_string[][64] = {
{"No error"}, {"Counter generic error"}, {"Counter is already set"}, {"Counter not ready"},
};
GpuCounter::GpuCounter() : Counter() {
counter_enabled_ = false;
parameter_set_ = new ParameterSet();
}
GpuCounter::~GpuCounter() { delete parameter_set_; }
bool GpuCounter::getResult(uint64_t* p_result) {
if (!p_result) {
return false;
}
*p_result = result_;
return true;
}
bool GpuCounter::setCounterBlock(pm4_profile::CounterBlock* p_cntr_group) {
if (!p_cntr_group) {
return false;
}
counter_block_ = p_cntr_group;
return true;
}
pm4_profile::CounterBlock* GpuCounter::getCounterBlock() { return counter_block_; }
bool GpuCounter::setEnable(bool b) {
// TODO: Validate counter
counter_enabled_ = b;
return true;
}
void GpuCounter::setResult(uint64_t result) { result_ = result; }
int GpuCounter::getLastError() { return error_code_; }
std::string GpuCounter::getErrorString(int error) {
if ((error >= 0) && (error < kHsaCounterErrorCodeMax)) {
std::string err_string(error_string[error]);
return err_string;
}
return "Incorrect error index";
}
bool GpuCounter::getParameter(uint32_t param, uint32_t& ret_size, void** pp_data) {
return parameter_set_->getParameter(param, ret_size, pp_data);
}
bool GpuCounter::setParameter(uint32_t param, uint32_t param_size, const void* p_data) {
bool ret_code;
error_code_ = kHsaCounterErrorCodeNoError;
ret_code = parameter_set_->setParameter(param, param_size, p_data);
if (ret_code == false) {
error_code_ = kHsaCounterErrorCodeAlreadySet;
}
return ret_code;
}
}
@@ -1,52 +0,0 @@
#ifndef _GPU_COUNTER_H_
#define _GPU_COUNTER_H_
#include "hsa_perf.h"
#include "parameter_set.h"
#include <stdlib.h>
#include <stdint.h>
#include <list>
namespace pm4_profile {
// @brief This class represent each CI performance counter
class GpuCounter : public pm4_profile::Counter {
public:
GpuCounter();
virtual ~GpuCounter();
virtual int getLastError();
virtual std::string getErrorString(int error);
virtual bool getResult(uint64_t* p_result);
virtual pm4_profile::CounterBlock* getCounterBlock();
virtual bool setEnable(bool b);
virtual bool isEnabled() { return counter_enabled_; }
virtual bool isResultReady() { return is_result_ready_; }
virtual bool getParameter(uint32_t param, uint32_t& ret_size, void** pp_data);
virtual bool setParameter(uint32_t param, uint32_t param_size, const void* p_data);
bool setCounterBlock(pm4_profile::CounterBlock* p_cntr_group);
void setResult(uint64_t result);
private:
bool counter_enabled_;
bool is_result_ready_;
uint64_t result_;
pm4_profile::ParameterSet* parameter_set_;
pm4_profile::CounterBlock* counter_block_;
uint32_t error_code_;
};
typedef std::list<GpuCounter*> GpuCounterList;
}
#endif // _GPU_COUNTER_H_
@@ -1,215 +0,0 @@
#include "gpu_countergroup.h"
#include "gpu_counter.h"
#include "gpu_enum.h"
using namespace pm4_profile;
namespace pm4_profile {
static char error_string[][64] = {
{"No error"}, {"Counter block error"}, {"Max counter reached"}, {"Unkown counter"}};
GpuCounterBlock::GpuCounterBlock() : CounterBlock() {
cntr_list_.clear();
parameter_set_ = new ParameterSet();
info_set_ = new InfoSet();
// Initialize pointer to NULL
pp_cntrs_ = NULL;
_initCounterBlockType();
}
GpuCounterBlock::~GpuCounterBlock() {
GpuCounterList::iterator it = cntr_list_.begin();
GpuCounterList::iterator it_end = cntr_list_.end();
for (; it != it_end; it++) {
if (*it) {
delete (*it);
}
}
cntr_list_.clear();
delete parameter_set_;
delete info_set_;
if (pp_cntrs_) {
free(pp_cntrs_);
pp_cntrs_ = NULL;
}
}
void GpuCounterBlock::_initCounterBlockType() {
block_type_ = HSA_EXT_TOOLS_COUNTER_BLOCK_TYPE_ASYNC;
}
Counter* GpuCounterBlock::createCounter() {
if (!_checkMaxNumOfCounters()) {
return NULL;
}
GpuCounter* p_cntr = new GpuCounter();
if (!p_cntr) {
return NULL;
}
cntr_list_.push_back(p_cntr);
return (Counter*)p_cntr;
}
bool GpuCounterBlock::destroyCounter(Counter* p_cntr) {
bool ret = false;
if (!p_cntr) {
return ret;
}
GpuCounterList::iterator it = cntr_list_.begin();
GpuCounterList::iterator it_end = cntr_list_.end();
for (; it != it_end; it++) {
if (*it == p_cntr) {
delete (*it);
cntr_list_.erase(it);
ret = true;
break;
}
}
return ret;
}
bool GpuCounterBlock::destroyAllCounters() {
GpuCounterList::iterator it = cntr_list_.begin();
GpuCounterList::iterator it_end = cntr_list_.end();
for (; it != it_end; it++) {
if (*it) {
delete (*it);
}
}
cntr_list_.clear();
return true;
}
Counter** GpuCounterBlock::getEnabledCounters(uint32_t& num) {
if (pp_cntrs_) {
free(pp_cntrs_);
pp_cntrs_ = NULL;
}
pp_cntrs_ = (Counter**)malloc(sizeof(GpuCounter*) * cntr_list_.size());
if (!pp_cntrs_) {
return NULL;
}
int cnt = 0;
GpuCounterList::iterator it = cntr_list_.begin();
GpuCounterList::iterator it_end = cntr_list_.end();
for (; it != it_end; it++) {
GpuCounter* p_cntr = (*it);
bool is_enabled;
is_enabled = p_cntr->isEnabled();
if (is_enabled) {
*(pp_cntrs_ + cnt) = (Counter*)*it;
cnt++;
}
}
num = cnt;
if (0 == num) {
return NULL;
}
return pp_cntrs_;
}
Counter** GpuCounterBlock::getAllCounters(uint32_t& num) {
if (pp_cntrs_) {
free(pp_cntrs_);
pp_cntrs_ = NULL;
}
pp_cntrs_ = (Counter**)malloc(sizeof(GpuCounter*) * cntr_list_.size());
if (!pp_cntrs_) {
return NULL;
}
int cnt = 0;
GpuCounterList::iterator it = cntr_list_.begin();
GpuCounterList::iterator it_end = cntr_list_.end();
for (; it != it_end; it++, cnt++) {
*(pp_cntrs_ + cnt) = (Counter*)*it;
}
num = cnt;
if (0 == num) {
return NULL;
}
return pp_cntrs_;
}
bool GpuCounterBlock::setInfo(GPU_BLK_INFOS blk_info, uint32_t size, void* data) {
return info_set_->setInfo(blk_info, size, data);
}
bool GpuCounterBlock::_checkMaxNumOfCounters() {
uint32_t num_enabled = _getNumOfEnabledCounters();
uint32_t* p_num_max = NULL;
uint32_t size = 0;
if (!getInfo(GPU_BLK_INFO_MAX_SIMULTANEOUS_COUNTERS, size, (void**)&p_num_max)) {
return false;
}
if (num_enabled >= *p_num_max) {
return false;
}
return true;
}
uint32_t GpuCounterBlock::_getNumOfEnabledCounters() {
uint32_t cnt = 0;
GpuCounterList::iterator it = cntr_list_.begin();
GpuCounterList::iterator it_end = cntr_list_.end();
for (; it != it_end; it++) {
GpuCounter* p_cntr = (*it);
bool is_enabled;
is_enabled = p_cntr->isEnabled();
if (is_enabled) {
cnt++;
}
}
return cnt;
}
std::string GpuCounterBlock::getErrorString(int error) {
if ((error >= 0) && (error < kHsaCounterBlockErrorCodeMaxError)) {
std::string err_string(error_string[error]);
return err_string;
}
return "incorrect error code";
}
bool GpuCounterBlock::getParameter(uint32_t param, uint32_t& ret_size, void** pp_data) {
return parameter_set_->getParameter(param, ret_size, pp_data);
}
bool GpuCounterBlock::setParameter(uint32_t param, uint32_t param_size, const void* pData) {
return parameter_set_->setParameter(param, param_size, pData);
}
bool GpuCounterBlock::getInfo(uint32_t info, uint32_t& ret_size, void** pp_data) {
return info_set_->getInfo(info, ret_size, pp_data);
}
}
@@ -1,70 +0,0 @@
#ifndef _GPU_COUNTER_GROUP_H_
#define _GPU_COUNTER_GROUP_H_
// This file contains declaration of Sea Island (CI) CounterBlock class.
#include "hsa_perf.h"
#include "gpu_counter.h"
#include "parameter_set.h"
#include "info_set.h"
#include "gpu_enum.h"
#include <stdlib.h>
#include <stdint.h>
namespace pm4_profile {
// This class represents one CI hardware block. Each block contains
// multiple performance counters.
class GpuCounterBlock : public pm4_profile::CounterBlock {
public:
GpuCounterBlock();
~GpuCounterBlock();
// NOTE [Suravee] : We specify CiPmu as a friend
// because the CiPmu needs to be able to setup info of
// the counter block.
friend class CiPmu;
friend class ViPmu;
friend class AiPmu;
std::string getErrorString(int error);
pm4_profile::Counter* createCounter();
virtual bool destroyCounter(pm4_profile::Counter* p_cntr);
virtual bool destroyAllCounters();
virtual pm4_profile::Counter** getEnabledCounters(uint32_t& num);
virtual pm4_profile::Counter** getAllCounters(uint32_t& num);
virtual bool getParameter(uint32_t param, uint32_t& ret_size, void** pp_data);
virtual bool setParameter(uint32_t param, uint32_t param_size, const void* p_data);
virtual bool getInfo(uint32_t info, uint32_t& ret_size, void** pp_data);
protected:
void _initCounterBlockType();
bool setInfo(GPU_BLK_INFOS blk_info, uint32_t size, void* data);
hsa_ext_tools_counter_block_type_t block_type_;
private:
bool _checkMaxNumOfCounters();
uint32_t _getNumOfEnabledCounters();
pm4_profile::ParameterSet* parameter_set_;
pm4_profile::InfoSet* info_set_;
GpuCounterList cntr_list_;
uint32_t error_code_;
// Pointer of buffer to store counter list
pm4_profile::Counter** pp_cntrs_;
};
} // pm4_profile
#endif // _GPU_COUNTER_GROUP_H_
@@ -1,65 +0,0 @@
#ifndef _GPU_ENUM_H_
#define _GPU_ENUM_H_
namespace pm4_profile {
// Enumeration containing GPU hardware block information
enum GPU_BLK_INFOS {
GPU_BLK_INFO_BLOCK_NAME,
GPU_BLK_INFO_ID,
GPU_BLK_INFO_MAX_SHADER_ENGINE_COUNT,
GPU_BLK_INFO_MAX_SHADER_ARRAY_COUNT,
GPU_BLK_INFO_MAX_INSTANCE_COUNT,
GPU_BLK_INFO_CONTROL_METHOD,
GPU_BLK_INFO_MAX_EVENT_ID,
GPU_BLK_INFO_MAX_SIMULTANEOUS_COUNTERS,
GPU_BLK_INFO_MAX_STREAMING_COUNTERS,
GPU_BLK_INFO_SHARED_HW_COUNTERS,
GPU_BLK_INFO_HAS_FILTERS,
// Trace-specific stuff
GPU_TRC_BLK_INFO_BUFFER_SIZE,
GPU_TRC_BLK_INFO_BUFFER_WRITE_POINTER_OFFSET,
GPU_TRC_BLK_INFO_BUFFER_WRAPPED,
GPU_TRC_BLK_INFO_DATA_SIZE_ESTIMATE,
GPU_TRC_BLK_INFO_DATA_POINTER,
};
/**
* Trace buffer parameters
*/
enum GPU_BLK_PARAMS {
// Allows user to specify the size of the trace buffers.
GPU_BLK_PARAM_TRACE_BUFFER_SIZE,
// If we decide to implement this functionality, this will allow the user
// to specify the number of trace buffers to create.
GPU_BLK_PARAM_TRACE_BUFFER_ARRAY,
// Specifies whether a new trace buffer should be used for each cmd buffer.
// This allows for better correlation of data back to the host application
// If this is enabled, and the user does not explicitly specify a
// TRACE_BUFFER_ARRAY, then the driver should automatically allocate
// additional buffers as needed so that as much of the application
// can be traced as possible, until the PerfExperiment is ended.
// If a TRACE_BUFFER_ARRAY is specified, then only as many buffers
// as specified should be created. If more cmd buffers get submitted
// than there are trace buffers, then the later cmd buffers should
// not be traced.
GPU_BLK_PARAM_TRACE_NEW_BUFFER_ON_SUBMIT,
};
// Enumeration containing GPU counter parameters
enum GPU_CNTR_PARAMS {
GPU_CNTR_PARAM_SHADERENGINE_ID,
GPU_CNTR_PARAM_SHADERARRAY_ID,
GPU_CNTR_PARAM_INSTANCE_ID,
GPU_CNTR_PARAM_EVENT_SELECT_ID,
GPU_CNTR_PARAM_SIMD_MASK,
GPU_CNTR_PARAM_PERF_MODE,
GPU_CNTR_PARAM_TRACE_TYPE,
};
}
#endif
@@ -1,436 +0,0 @@
#ifndef _HSA_PERF_H_
#define _HSA_PERF_H_
#include "rocr_profiler.h"
#if !defined(AMD_AMP_HSA_INCLUDES)
#include <map>
#include <string>
#include <stdlib.h>
#include <stdint.h>
#endif
namespace pm4_profile {
class Pmu;
class Counter;
class CounterBlock;
class TraceGroup;
class CommandWriter;
class DefaultCmdBuf;
// @brief This is an abstract class for defining a CounterBlock. Each
// CounterBlock contains a set of Counters that often belong to the
// same functional unit
//
// For AMD GPU, this can represent blocks of Counters in each HW block
// (e.g. SQ, SQI, CP, etc.).
// For AMD CPU, this can represent blocks of core PMCs, NB PMCs, L2I PMCs
// on each CPU device
//
// Generally, CounterBlocks are created and initialized by the \ref Pmu class.
// Users can query them by calling \ref Pmu::getAllCounterBlocks() or
// \ref Pmu::getCounterBlockById(). A CounterBlock is enabled if it contains
// enabled Counters in the block.
//
// Users can manage Counters in each GounterBlock (e.g. create, destroy,
// enable and disable). To specify a Counter, users simply call \ref
// createCounter. Then it can be enabled or disabled using \ref
// Counter::setEnable. When a Counter is enabled, it is checked against the
// CounterBlock checks to make sure that the enabled-counter is valid and is
// not conflicting with the current Counters in the block.
class CounterBlock {
public:
typedef enum HsaCounterBlockErrorCode {
// Generic CounterBlock error
kHsaCounterBlockErrorCodeNoError = 0x0,
// Generic CounterBlock error
kHsaCounterBlockErrorCodeGenericError,
// The maximum number of Counters in the block is reached.
kHsaCounterBlockErrorCodeMaxNumCounterReached,
// The counter does not belong to this block.
kHsaCounterBlockErrorCodeUnknownCounter,
// The counter does not belong to this block.
kHsaCounterBlockErrorCodeMaxError
} HsaCounterBlockErrorCode;
// Destructor of CounterBlock.
virtual ~CounterBlock() {}
// Given and error number reported from getLastError or returned from a
// function call, retreive the corresponding stl string.
// @param[in] error The error corresponding to a call to getLastError
// or a return code from a function call.
// Return An stl string representing a text corresponding to the error
// number.
// If invalid error code is given, the returned string is empty.
virtual std::string getErrorString(int error) = 0;
// Create an Counter object return a pointer to caller.
// Return On success, this function returns a pointer to Counter
// On failure, this function returns NULL
// Possible error codes are:
// kHSAPerfErrorCodesUnmodifiableState
// kHsaCounterBlockErrorCodeMaxNumCounterReached
virtual Counter* createCounter() = 0;
// Destroy the Counter. The CounterBlock which owns the Counter must be in
// disabled state.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidAargs
// kHSAPerfErrorCodesUnmodifiableState
// kHsaCounterBlockErrorCodeUnknownCounter
virtual bool destroyCounter(Counter* p_counter) = 0;
// Destroy all counters in the block. The CounterBlock must be in disable
// state.
// Return true or false.
// Possible error codes are:
// kHSAPerfErrorCodesUnmodifiableState
virtual bool destroyAllCounters() = 0;
// Get a list of pointers to the enabled Counters in this CounterBlock.
// note The Counter must be created by the same CounterBlock object using
// createCounter().
// @param[in] num The number of Counter pointers returned.
// Return
// return a list of pointers to the enabled Counters.
// return NULL if no counter is enabled.
virtual Counter** getEnabledCounters(uint32_t& num) = 0;
// Get a list of pointers to the all Counters in this CounterBlock.
// note The Counter must be created by the same CounterBlock object using
// createCounter().
// @param[in] num The number of Counter pointers returned.
// Return
// return a list of pointers in the CounterBlock.
// return NULL if no counter is enabled.
virtual Counter** getAllCounters(uint32_t& num) = 0;
// Query value of the parameter specified by param
// @param[in] param The enumeration of parameter to be queried
// @param[out] return_size The returned size of data
// @param[out] pp_data The pointer to the returned data. The API is
// responsible for managing the memory to store the information as specified
// by return_size.
//
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidParam
// kHSAPerfErrorCodesInvalidParamSize
// kHSAPerfErrorCodesInvalidParamData
virtual bool getParameter(uint32_t param, uint32_t& return_size, void** pp_data) = 0;
// Set value for the parameter specified by param
// @param[in] param The enumeration of parameter to be queried
// @param[out] param_size The size of data
// @param[out] p_data The pointer to the data to be set. Users are responsible
// for deallocating the memory of p_data after calling the API.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesUnmodifiableState
// kHSAPerfErrorCodesInvalidParam
// kHSAPerfErrorCodesInvalidParamSize
// kHSAPerfErrorCodesInvalidParamData
virtual bool setParameter(uint32_t param, uint32_t param_size, const void* p_data) = 0;
// Query value of the information specified by info
// @param[in] info The enumeration of information to be queried
// @param[out] Return_size The returned size of data
// @param[out] pp_data The pointer to the returned data
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidInfo
// kHSAPerfErrorCodesInvalidInfoSize
// kHSAPerfErrorCodesInvalidInfoData
virtual bool getInfo(uint32_t info, uint32_t& return_size, void** pp_data) = 0;
}; // class CounterBlock
// This is an abstract class for defining a TraceGroup. TraceGroup inherits
// CounterBlock and add interfaces for managing trace buffer. It also supports
// user-data insertion into trace. This allows users to insert arbitary data
// (e.g. markers) into trace which and can be used to correlating a specific
// events to the collected trace data.
class TraceGroup : public CounterBlock {
public:
typedef enum HsaTraceGroupErrorCode {
// Generic TraceGroup error
HsaTraceGroupErrorCodeGenericError = 0x100,
} HsaTraceGroupErrorCode;
// Destructor of TraceGroup.
virtual ~TraceGroup() {}
// Obtains the number of buffers which were collected as part of
// the trace.
// Return The number of collected buffers.
virtual uint32_t getCollectedBufferCount() = 0;
// Locks a trace buffer for host access.
// @param[in] buffer_id The index of the buffer to be locked.
// Return true or false
virtual bool lock(uint32_t buffer_id) = 0;
// Unlock a trace buffer that was previously locked.
// @param[in] buffer_id The index of the buffer to be unlocked.
// Return true or false
virtual bool unlock(uint32_t buffer_id) = 0;
// Inserts data (e.g. trace marker) into the trace.
// @param[in] type The type of data to be inserted.
// @param[in] p_data The data to be inserted.
// @param[in] data_size The size of data to be inserted.
// Return true or false
virtual bool insertUserData(uint32_t type, void* p_data, uint32_t data_size) = 0;
}; // class TraceGroup
// This is an abstract class for defining a performance Counter.
// Users can obtain a Counter from \ref CounterBlock::createCounter().
// Once obtained, users can set up Counter parameters, and enable it using
// \ref Counter::setEnable().
//
// There are several types of Counter as defined in \ref
// HsaCounterBlockTypeMask.
// Only the supported Counter type can be added to the CounterBlock.
//
// Each Counter can store Counter-specific parameters. The Counter is used to
// specify types of event to be counted.
class Counter {
public:
typedef enum HsaCounterErrorCode {
// Generic Counter error
kHsaCounterErrorCodeNoError = 0x0,
// Generic Counter error
kHsaCounterErrorCodeGenericError = 0x1,
// Counter already error
kHsaCounterErrorCodeAlreadySet = 0x2,
// Counter result is not ready.
kHsaCounterErrorCodeResultNotReady = 0x3,
// Max counter error num
kHsaCounterErrorCodeMax,
} HsaCounterErrorCode;
// Destructor of Counter
virtual ~Counter() {}
// Retrieve the last error code generated. This should be checked when
// values returned are NULL or void.
// Return an integer corresponding to the last error reported.
virtual int getLastError() = 0;
// Given and error number reported from getLastError or returned from a
// function call, retreive the corresponding stl string.
// @param[in] error The error corresponding to a call to getLastError
// or a return code from a function call.
// Return An stl string representing a text corresponding to the error
// number. If invalid error code is given, the returned string is empty.
virtual std::string getErrorString(int error) = 0;
// Get the \ref CounterBlock which owns this counter.
// Return
// On success, it returns a pointer to the CounterBlock.
// On Failure, it returns NULL.
virtual CounterBlock* getCounterBlock() = 0;
// Enable or disable the Counter.
// @param[in] b Set to true to enable the CounterBlock.
// Return
// return true when successfully set the state.
// return false otherwise.
// In case of the current state already is set to the specified value,
// the API returns true.
// Possible error codes are:
// kHSAPerfErrorCodesUnmodifiableState
virtual bool setEnable(bool b) = 0;
// Return the current state of the Counter.
// Return true or false
virtual bool isEnabled() = 0;
// Return the status of this Counter whether the result is available.
// Return true or false
virtual bool isResultReady() = 0;
// Query Counter result
// note Must be implemented by derived classes
// @param[out] p_result The pointer containing the returned result.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidAargs
// kHsaCounterErrorCodeResultNotReady
virtual bool getResult(uint64_t* p_result) = 0;
// Query value of the parameter specified by param
// @param[in] param The enumeration of parameter to be queried
// @param[out] Return_size The returned size of data
// @param[out] pp_data The pointer to the returned data. The API is
// responsible for managing the memory to store the information as
// specified by return_size.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidParam
// kHSAPerfErrorCodesInvalidParamSize
// kHSAPerfErrorCodesInvalidParamData
virtual bool getParameter(uint32_t param, uint32_t& return_size, void** pp_data) = 0;
// Set value for the parameter specified by param
// @param[in] param The enumeration of parameter to be queried
// @param[out] param_size The size of data
// @param[out] p_data The pointer to the data to be set. Users are responsible
// for deallocating the memory of p_data after calling the API.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesUnmodifiableState
// kHSAPerfErrorCodesInvalidParam
// kHSAPerfErrorCodesInvalidParamSize
// kHSAPerfErrorCodesInvalidParamData
virtual bool setParameter(uint32_t param, uint32_t param_size, const void* p_data) = 0;
}; // class Counter
class Pmu {
public:
// Enumeration of Pmu error codes
typedef enum HsaPmuErrorCode {
// Generic PMU error
kHsaPmuErrorCodeNoError = 0x0,
// Unknown CounterBlock ID
kHsaPmuErrorCodeUnknownCounterBlockId,
// No CounterBlock exists
kHsaPmuErrorCodeNoCounterBlock,
// The previously operation is not valid. This could be due to
// invalid transition from the current state.
kHsaPmuErrorCodeInvalidOperation,
// PMU is not currently available (e.g. PMU is currently
// in-used by others)
kHsaPmuErrorCodeNotAvailable,
// PMU is not currently available (e.g. PMU is currently
// in-used by others)
kHsaPmuErrorCodeErrorState,
// PMU result is timeout
kHsaPmuErrorCodeTimeOut,
// Max error count
kHsaPmuErrorCodeMax
} HsaPmuErrorCode;
// Destructor of PMU.
// note This stops the performance counters if running and releases
// any resources used by the PMU.
virtual ~Pmu() {}
// Retrieve the last error code generated. This should be checked when
// values returned are NULL or void.
// Return an integer corresponding to the last error reported.
virtual int getLastError() = 0;
// Given and error number reported from getLastError or returned from a
// function call, retreive the corresponding stl string.
// @param[in] error The error corresponding to a call to getLastError
// or a return code from a function call.
// Return An stl string representing a text corresponding to the error
// number. If invalid error code is given, the returned string is empty.
virtual std::string getErrorString(int error) = 0;
// Get CounterBlock from Id
// @param[in] id ID of the target CounterBlock
// Return
// On success, it returns a pointer to specified CounterBlock.
// On Failure, it returns NULL.
// Possible error codes are:
// kHsaPmuErrorCodeUnknownCounterBlockId.
virtual CounterBlock* getCounterBlockById(uint32_t id) = 0;
// Get all available CounterBlock
// @param[out] num_block The returned number of CounterBlocks
// Return On success, it returns an array of CounterBlock pointers.
// On Failure, it returns NULL.
virtual CounterBlock** getAllCounterBlocks(uint32_t& num_block) = 0;
// Get current PMU profiling state.
// Return The PMU profiling state as defined in \ref PMU_PROFILE_STATES
virtual rocr_pmu_state_t getCurrentState() = 0;
// Start profiling on the PMU.
// @param[in] reset_counter indicates whether reset counter before
// recording. Default is reset counters.
// note This function must be implemented by children classes.
// Return true or false
// Possible error codes are:
// kHsaPmuErrorCodeInvalidOperation
// kHsaPmuErrorCodeNotAvailable
virtual bool begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter, bool reset = true) = 0;
// Stop profiling on the PMU.
// note This function must be called after \ref begin().
// note This function must be implemented by children classes.
// Return true or false
// Possible error codes are:
// kHsaPmuErrorCodeInvalidOperation
virtual bool end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter) = 0;
// Initializes the handle of buffer used to collect PMC data
// @param pmcBuffer The buffer pointer
// @param cmdBufSz Size in terms of bytes
virtual bool setPmcDataBuff(uint8_t* pmcBuffer, uint32_t pmcBuffSz) = 0;
// Query value of the parameter specified by param
// @param[in] param The enumeration of parameter to be queried
// @param[out] Return_size The returned size of data
// @param[out] pp_data The pointer to the returned data. The API is
// responsible for managing the memory to store the information as
// specified by return_size.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidParam
// kHSAPerfErrorCodesInvalidParamSize
// kHSAPerfErrorCodesInvalidParamData
virtual bool getParameter(uint32_t param, uint32_t& return_size, void** pp_data) = 0;
// Set value for the parameter specified by param
// @param[in] param The enumeration of parameter to be queried
// @param[out] param_size The size of data
// @param[out] p_data The pointer to the data to be set. Users are responsible
// for deallocating the memory of p_data after calling the API.
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesUnmodifiableState
// kHSAPerfErrorCodesInvalidParam
// kHSAPerfErrorCodesInvalidParamSize
// kHSAPerfErrorCodesInvalidParamData
virtual bool setParameter(uint32_t param, uint32_t param_size, const void* p_data) = 0;
// Query value of the information specified by info
// @param[in] info The enumeration of information to be queried
// @param[out] Return_size The returned size of data
// @param[out] pp_data The pointer to the returned data
// Return true or false
// Possible error codes are:
// kHSAPerfErrorCodesInvalidInfo
// kHSAPerfErrorCodesInvalidInfoSize
// kHSAPerfErrorCodesInvalidInfoData
virtual bool getInfo(uint32_t info, uint32_t& return_size, void** pp_data) = 0;
// Returns number of shader engines per block
// for the blocks featured shader engines instancing
virtual uint32_t getNumSe() = 0;
}; // class Pmu
} // pm4_profile
#endif // _HSA_PERF_H_
@@ -1,74 +0,0 @@
#include "info_set.h"
#include "var_data.h"
using namespace std;
namespace pm4_profile {
InfoSet::InfoSet() {
releaseParameters();
info_table_.clear();
p_data_ = NULL;
}
InfoSet::~InfoSet() {
releaseParameters();
info_table_.clear();
free(p_data_);
p_data_ = NULL;
}
bool InfoSet::setInfo(uint32_t info, uint32_t info_size, void* p_data) {
if (info_table_.end() != info_table_.find(info)) {
return false;
}
VarData data;
if (!data.set(info_size, p_data)) {
return false;
}
info_table_.insert(VarDataMap::value_type(info, data));
return true;
}
bool InfoSet::getInfo(uint32_t info, uint32_t& ret_size, void** pp_data) {
if (!pp_data || (0 == info_table_.size())) {
return false;
}
VarDataMap::iterator it = info_table_.find(info);
if (it == info_table_.end()) {
return false;
}
int size = it->second.getSize();
if (size == 0) {
return false;
}
free(p_data_);
p_data_ = NULL;
p_data_ = malloc(size);
if (!p_data_) {
return false;
}
*pp_data = p_data_;
ret_size = info_table_[info].get(size, *pp_data);
return true;
}
void InfoSet::releaseParameters() {
VarDataMap::iterator it = info_table_.begin();
VarDataMap::iterator table_end = info_table_.end();
for (; it != table_end; it++) {
it->second.clear();
}
return;
}
} // pm4_profile
@@ -1,48 +0,0 @@
#ifndef _INFO_SET_H_
#define _INFO_SET_H_
// This file contains declaration of IInfoSet class.
#include "hsa_perf.h"
#include "var_data.h"
#include <stdlib.h>
#include <stdint.h>
namespace pm4_profile {
// An abstract class defining a container to hold a information data set
// (e.g. PMU info, CounterGroup info, etc.). Unlike \ref IParameterSet,
// This class allows only the children of the class to set the information.
class InfoSet {
public:
// IInfoSet constructor
InfoSet();
// IInfoSet destructor
virtual ~InfoSet();
// Query value of the information specified by info
// @param[in] info The enumeration of information to be queried
// @param[out] ret_size The returned size of data
// @param[out] pp_data The pointer to the returned data
// /return true or false
bool getInfo(uint32_t info, uint32_t& ret_size, void** pp_data);
// Set value for the information specified by info
// @param[in] info The enumeration of information to be queried
// @param[out] info_size The size of data
// @param[out] p_data The pointer to the data to be set
// /return true or false
bool setInfo(uint32_t info, uint32_t info_size, void* p_data);
private:
// Remove all data in the parameter table
void releaseParameters();
// InfoSet property: The info table
VarDataMap info_table_;
// Pointer to the buffer used in getInfo
void* p_data_;
};
}
#endif
@@ -1,74 +0,0 @@
#include "parameter_set.h"
using namespace std;
namespace pm4_profile {
ParameterSet::ParameterSet() {
releaseParameters();
param_table_.clear();
p_data_ = NULL;
}
ParameterSet::~ParameterSet() {
releaseParameters();
param_table_.clear();
free(p_data_);
p_data_ = NULL;
}
bool ParameterSet::setParameter(uint32_t param, uint32_t param_size, const void* p_data) {
if (param_table_.end() != param_table_.find(param)) {
return false;
}
VarData data;
if (!data.set(param_size, p_data)) {
return false;
}
param_table_.insert(VarDataMap::value_type(param, data));
return true;
}
bool ParameterSet::getParameter(uint32_t param, uint32_t& ret_size, void** pp_data) {
if (!pp_data || (0 == param_table_.size())) {
return false;
}
VarDataMap::iterator it = param_table_.find(param);
if (it == param_table_.end()) {
return false;
}
int size = it->second.getSize();
if (size == 0) {
return false;
}
// for NULL pointer, free does nothing
free(p_data_);
p_data_ = malloc(size);
if (!p_data_) {
return false;
}
// store the pointer to be freed
*pp_data = p_data_;
ret_size = param_table_[param].get(size, *pp_data);
return true;
}
bool ParameterSet::releaseParameters() {
VarDataMap::iterator it = param_table_.begin();
VarDataMap::iterator table_end = param_table_.end();
for (; it != table_end; it++) {
it->second.clear();
}
return true;
}
} // pm4_profile
@@ -1,75 +0,0 @@
#ifndef _PARAMETER_SET_H_
#define _PARAMETER_SET_H_
/*!
\note This file contains declaration of IParameterSet class.
*/
#include "hsa_perf.h"
#include "var_data.h"
#include <stdlib.h>
#include <stdint.h>
namespace pm4_profile {
/*!
A class defining a container to hold parameter data set
(e.g. PMU parameter, CounterGroup parameter, etc.).
*/
class ParameterSet {
public:
/*!
Enumeration containing types of parameters
*/
enum parameter {
PARAM_MAX,
};
/*! IParameterSet constructor */
ParameterSet();
/*! IParameterSet destructor */
virtual ~ParameterSet();
/*!
Query value of the parameter specified by param
@param[in] param The enumeration of parameter to be queried
@param[out] ret_size The returned size of data
@param[out] pp_data The pointer to the returned data
/return true or false
*/
bool getParameter(
/*in*/ uint32_t param,
/*out*/ uint32_t& ret_size,
/*out*/ void** pp_data);
/*!
Set value for the parameter specified by param
@param[in] param The enumeration of parameter to be queried
@param[out] param_size The size of data
@param[out] p_data The pointer to the data to be set
/return true or false
*/
bool setParameter(
/*in*/ uint32_t param,
/*in*/ uint32_t param_size,
/*in*/ const void* p_data);
private:
/*!
Remove all data in the parameter table
*/
bool releaseParameters();
/*!
IParameterSet property: The parameter table
*/
VarDataMap param_table_;
/*!
Pointer to the buffer used in getParameter
*/
void* p_data_;
};
}
#endif // _PARAMETER_SET_H_
@@ -0,0 +1,92 @@
#ifndef _HSA_PERF_H_
#define _HSA_PERF_H_
#include <vector>
#include <map>
#include <string>
#include <stdint.h>
namespace pm4_profile {
class DefaultCmdBuf;
class CommandWriter;
typedef std::vector<uint32_t> CountersVec;
typedef std::map<uint32_t, CountersVec> CountersMap;
class Pmu {
public:
// Enumeration of Pmu error codes
typedef enum ErrorCode {
// Generic PMU error
kErrorCodeNoError = 0x0,
// Unknown CounterBlock ID
kErrorCodeUnknownCounterBlockId,
// No CounterBlock exists
kErrorCodeNoCounterBlock,
// The previously operation is not valid. This could be due to
// invalid transition from the current state.
kErrorCodeInvalidOperation,
// PMU is not currently available (e.g. PMU is currently
// in-used by others)
kErrorCodeNotAvailable,
// PMU is not currently available (e.g. PMU is currently
// in-used by others)
kErrorCodeErrorState,
// PMU result is timeout
kErrorCodeTimeOut,
// Max error count
kErrorCodeMax
} ErrorCode;
// Destructor of PMU.
// note This stops the performance counters if running and releases
// any resources used by the PMU.
virtual ~Pmu() {}
// Retrieve the last error code generated. This should be checked when
// values returned are NULL or void.
// Return an integer corresponding to the last error reported.
virtual int getLastError() = 0;
// Given and error number reported from getLastError or returned from a
// function call, retreive the corresponding stl string.
// @param[in] error The error corresponding to a call to getLastError
// or a return code from a function call.
// Return An stl string representing a text corresponding to the error
// number. If invalid error code is given, the returned string is empty.
virtual std::string getErrorString(int error) = 0;
// Start profiling on the PMU.
// @param[in] reset_counter indicates whether reset counter before
// recording. Default is reset counters.
// note This function must be implemented by children classes.
// Return true or false
// Possible error codes are:
// kErrorCodeInvalidOperation
// kErrorCodeNotAvailable
virtual void begin(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter,
const CountersMap& countersMap) = 0;
// Stop profiling on the PMU.
// note This function must be called after \ref begin().
// note This function must be implemented by children classes.
// Return true or false
// Possible error codes are:
// kErrorCodeInvalidOperation
virtual uint32_t end(DefaultCmdBuf* cmdBuff, CommandWriter* cmdWriter,
const CountersMap& countersMap, void* dataBuff) = 0;
// Returns number of shader engines per block
// for the blocks featured shader engines instancing
virtual uint32_t getNumSe() = 0;
}; // class Pmu
} // pm4_profile
#endif // _HSA_PERF_H_
@@ -1,254 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2015, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _ROCR_PROFILER_H_
#define _ROCR_PROFILER_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
#define HSA_TOOLS_API __attribute__((dllexport))
#else
#define HSA_TOOLS_API __declspec(dllexport) // Note: actually gcc seems
// to also supports this
// syntax.
#endif
#ifndef DLL_LOCAL
#define DLL_LOCAL
#endif
#else // defined _WIN32 || defined __CYGWIN__
#if __GNUC__ >= 4
#define HSA_TOOLS_API __attribute__((visibility("default")))
#ifndef DLL_LOCAL
#define DLL_LOCAL __attribute__((visibility("hidden")))
#endif
#else
#define HSA_TOOLS_API
#ifndef DLL_LOCAL
#define DLL_LOCAL
#endif
#endif
#endif // defined _WIN32 || defined __CYGWIN__
//---------------------------------------------------------------------------//
// @brief Enumeration of various information that is set for a counter. //
// @detail This enumeration defines the various counter info that could be //
// used in a counter. This is used by a counter object to specify //
// its type and other conditions that are needed to retrieve a //
// counter value. //
//---------------------------------------------------------------------------//
typedef enum hsa_ext_tools_counter_parameter_s {
// Event index of a counter
HSA_EXT_TOOLS_COUNTER_PARAMETER_EVENT_INDEX = 0,
// Simd mask of a counter
HSA_EXT_TOOLS_COUNTER_PARAMETER_SIMD_MASK = 1,
// Shader engine mask of a counter
HSA_EXT_TOOLS_COUNTER_PARAMETER_SHADER_MASK = 2,
// Max counter info index
HSA_EXT_TOOLS_COUNTER_PARAMETER_INFO_MAX
} hsa_ext_tools_counter_parameter_t;
//---------------------------------------------------------------------------//
// @brief Enumeration of counter block type mask //
// @details This enumeration define the bit mask representing types of //
// counter broup supported by HSA. This is used by counter block object to //
// specify its type. //
//---------------------------------------------------------------------------//
typedef enum hsa_ext_tools_counter_block_type_s {
// Unknown counter block type
HSA_EXT_TOOLS_COUNTER_BLOCK_TYPE_UNKNOWN = 0,
// The CounterBlock of this type can be access at anytime.
// note Examples are software Counters and CPU Counters.
HSA_EXT_TOOLS_COUNTER_BLOCK_TYPE_SYNC = 1,
// The CounterBlock type can be access asynchronously.
// It is required that the Counter must be stopped
// before accessing.
HSA_EXT_TOOLS_COUNTER_BLOCK_TYPE_ASYNC = 2,
// The CounterBlock of this counter block is used for generating
// trace.
HSA_EXT_TOOLS_COUNTER_BLOCK_TYPE_TRACE = 3,
// Max CounterBlock type
HSA_EXT_TOOLS_COUNTER_BLOCK_TYPE_MAX
} hsa_ext_tools_counter_block_type_t;
//---------------------------------------------------------------------------//
// @brief Enumeration of various information that is set for a counter block.//
// @detail This enumeration defines the various info that could be used //
// in a counter block. This is used by a counter object to specify its type //
// and other conditions that are needed for a counter block. //
//---------------------------------------------------------------------------//
/*
typedef enum hsa_ext_tools_counter_block_info_s {
// Index of a counter block
HSA_EXT_TOOLS_COUNTER_BLOCK_INFO_EVENT_INDEX = 0,
// Shader bits of a counter block
HSA_EXT_TOOLS_COUNTER_BLOCK_INFO_SHADER_BITS = 1,
// Simd mask of a counter
HSA_EXT_TOOLS_COUNTER_BLOCK_INFO_CONTROL_METHOD = 2,
// Max index of counter block info
HSA_EXT_TOOLS_COUNTER_BLOCK_INFO_MAX
} hsa_ext_tools_counter_block_info_t;
*/
//---------------------------------------------------------------------------//
// Enumeration for the methods used to index into the correct registers. //
//---------------------------------------------------------------------------//
/*
typedef enum hsa_ext_tools_counter_index_method_s {
// No index
HSA_EXT_TOOLS_COUNTER_INDEX_METHOD_BY_NONE = 0,
// Index by block instance
HSA_EXT_TOOLS_COUNTER_INDEX_METHOD_BY_INSTANCE = 1,
// Index by shader engine
HSA_EXT_TOOLS_COUNTER_INDEX_METHOD_BY_SHADER_ENGINE = 2,
// Index by shader and instance
HSA_EXT_TOOLS_COUNTER_INDEX_METHOD_BY_SHADER_ENGINE_ANDINSTANCE = 3
} hsa_ext_tools_counter_index_method_t;
*/
//---------------------------------------------------------------------------//
// Enumeration for the HSAPerf generic error codes //
//---------------------------------------------------------------------------//
/*
typedef enum hsa_ext_tools_error_codes_s {
// Successful
HSA_EXT_TOOLS_ERROR_CODE_OK = 0,
// Generic error code
HSA_EXT_TOOLS_ERROR_CODE_ERROR,
// Generic invalid HSAPerf API arguments
HSA_EXT_TOOLS_ERROR_CODE_INVALID_ARGS,
// The operation is not permit due to currently in the unmodifiable
// HSAPerf state .
HSA_EXT_TOOLS_ERROR_CODE_UNMODIFIABLE_STATE,
// The hsa_ext_tools_set_pmu_parameter() or
// hsa_ext_tools_get_pmu_parameter() API contains invalid parameter value.
HSA_EXT_TOOLS_ERROR_CODE_INVALID_PARAM,
// The hsa_ext_tools_set_pmu_parameter() or
// hsa_ext_tools_get_pmu_parameter() API contains invalid parameter size
// or return size.
HSA_EXT_TOOLS_ERROR_CODE_INVALID_PARAM_SIZE,
// The hsa_ext_tools_set_pmu_parameter() or
// hsa_ext_tools_get_pmu_parameter() API contains invalid
// pointer (e.g. NULL).
HSA_EXT_TOOLS_ERROR_CODE_INVALID_PARAM_DATA,
// The hsa_ext_tools_get_pmu_info() API contains invalid info value.
HSA_EXT_TOOLS_ERROR_CODE_INVALID_INFO,
// The hsa_ext_tools_get_pmu_info() API contains invalid info
// size (e.g. zero).
HSA_EXT_TOOLS_ERROR_CODE_INVALID_INFO_SIZE,
// The hsa_ext_tools_get_pmu_info() API contains invalid
// data (e.g. NULL).
HSA_EXT_TOOLS_ERROR_CODE_INVALID_INFO_DATA
} hsa_ext_tools_error_codes_t;
*/
//---------------------------------------------------------------------------//
// Enumeration for Pmu profiling state //
//---------------------------------------------------------------------------//
typedef enum rocr_pmu_state_s {
// Profiling idle. In this state, changes can be made to
// the PMU, counter blocks, counters. This state can represent
// the moment prior to calling begin or after calling
// hsa_ext_tools_pmu_wait_for_completion().
ROCR_PMU_STATE_IDLE,
// Profiling start. In this state, changes cannot be made to
// the PMU, counter block, counters. The PMU is collecting
// performance counter data. This state represents
// the moment after calling hsa_ext_tools_pmu_begin() and before calling
// hsa_ext_tools_pmu_end()
ROCR_PMU_STATE_START,
// Profiling stop. In this state, changes cannot be made to
// the PMU, counter blocks, Counters. PMU has stopped the
// performance counter data collection. However, the result
// might not yet be available. This state represents
// the moment after calling hsa_ext_tools_pmu_end() and before the call
// to hsa_ext_tools_pmu_wait_for_completion() has returned success.
ROCR_PMU_STATE_STOP
} rocr_pmu_state_t;
//---------------------------------------------------------------------------//
// Opaque pointer to HSA performance monitor unit (PMU) //
//---------------------------------------------------------------------------//
// typedef void * hsa_ext_tools_pmu_t;
//---------------------------------------------------------------------------//
// Opaque pointer to HSA counter block //
//---------------------------------------------------------------------------//
// typedef void * hsa_ext_tools_counter_block_t;
//---------------------------------------------------------------------------//
// Opaque pointer to HSA counter //
//---------------------------------------------------------------------------//
// typedef void * hsa_ext_tools_counter_t;
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _ROCR_PROFILER_H_
@@ -1,48 +0,0 @@
#include <string.h>
#include "var_data.h"
namespace pm4_profile {
VarData::VarData() {
size_ = 0;
p_data_ = NULL;
}
VarData::~VarData() {}
void VarData::clear() {
size_ = 0;
if (p_data_) {
free(p_data_);
p_data_ = NULL;
}
}
bool VarData::set(uint32_t size, const void* p_data) {
if (!p_data || (size == 0)) {
return false;
}
clear();
if (NULL == (p_data_ = malloc(size))) {
return false;
}
memcpy(p_data_, p_data, size);
size_ = size;
return true;
}
uint32_t VarData::get(uint32_t size, void* p_data) {
if (!p_data || !size || !p_data_ || !size_) {
return 0;
}
uint32_t ret_size = size < size_ ? size : size_;
memcpy(p_data, p_data_, ret_size);
return ret_size;
}
} // pm4_profile
@@ -1,65 +0,0 @@
#ifndef _VAR_DATA_H_
#define _VAR_DATA_H_
/*!
\note This file contains declaration of IVarData class.
*/
#include "hsa_perf.h"
#include <map>
#include <stdlib.h>
#include <stdint.h>
namespace pm4_profile {
/*!
This abstract class implements variable-size storage for information and
parameter
sets.
*/
class VarData {
public:
/*! Constructor for IVarData */
VarData();
/*! Destructor for IVarData */
~VarData();
/*! Deallocate the memory and clean up */
void clear();
/*!
Set the data to be stored.
@param[in] size Size of data to be stored.
@param[in] p_data Pointer to data to be stored.
\return true or false
*/
bool set(uint32_t size, const void* p_data);
/*!
Query the data that was stored.
@param[in] size Size (in bytes) of the memory pointed to by p_data.
This determines maximum size of the returned data.
@param[in,out] p_data Pointer to the result buffer.
\return Size (in bytes) of the returned result which is coppied into
the buffer pointed to by p_data.
*/
uint32_t get(uint32_t size, void* p_data);
/*!
Get size of the current data stored
\return Size (in bytes) of the data stored.
*/
uint32_t getSize() { return size_; }
private:
/*! Size of data being stored */
uint32_t size_;
/*! Pointer to the stored data */
void* p_data_;
};
typedef std::map<uint32_t, VarData> VarDataMap;
}
#endif
@@ -1,141 +0,0 @@
#ifndef _VI_PMU_H_
#define _VI_PMU_H_
#include "hsa.h"
#include "cmdwriter.h"
#include "hsa_perf.h"
#include "info_set.h"
#include "parameter_set.h"
#include "vi_blockinfo.h"
#include "rocr_profiler.h"
#include <stdlib.h>
#include <stdint.h>
#include <map>
namespace pm4_profile {
typedef std::map<HsaViCounterBlockId, pm4_profile::CounterBlock*> ViCounterBlockMap;
// This class implement the VI PMU. It is responsible for setting up
// CounterGroups to represent each VI hardware block which exposes performance
// counters.
class ViPmu : public pm4_profile::Pmu {
public:
ViPmu();
~ViPmu();
// Returns number of shader engines per block
// for the blocks featured shader engines instancing
uint32_t getNumSe() { return num_se_; }
// Initializes the handle of buffer used to collect PMC data
bool setPmcDataBuff(uint8_t* pmcBuffer, uint32_t pmcBuffSz);
int getLastError();
std::string getErrorString(int error);
virtual bool begin(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter* cmdWriter,
bool reset = true);
virtual bool end(pm4_profile::DefaultCmdBuf* cmdBuff, pm4_profile::CommandWriter* cmdWriter);
// IPMU inherits the IParameterSet and IInfoSetso we implement it
// through composition and function forwarding
bool getParameter(uint32_t param, uint32_t& ret_size, void** pp_data);
bool setParameter(uint32_t param, uint32_t param_size, const void* p_data);
bool getInfo(uint32_t info, uint32_t& ret_size, void** pp_data);
pm4_profile::CounterBlock* getCounterBlockById(uint32_t id);
rocr_pmu_state_t getCurrentState() { return profiler_state_; }
pm4_profile::CounterBlock** getAllCounterBlocks(uint32_t& num_groups);
private:
// Addr of Counter Data Buffer
uint32_t* pmcData_;
// Size of Counter Data Buffer
uint32_t pmcDataSz_;
void Init();
bool initCounterBlock();
bool isResultReady();
// Clear CounterBlockMap
void clearCounterBlockMap();
// Reset SQ and CB counters
void ResetCounterBlocks(pm4_profile::DefaultCmdBuf* cmdBuff,
pm4_profile::CommandWriter* cmdWriter);
// Program SQ block related counters
uint32_t ProgramSQCntrs(uint32_t sqRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TA block related counters
uint32_t ProgramTaCntrs(uint32_t taRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TCA block related counters
uint32_t ProgramTcaCntrs(uint32_t tcaRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TCC block related counters
uint32_t ProgramTccCntrs(uint32_t tccRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TCP block related counters
uint32_t ProgramTcpCntrs(uint32_t tcpRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Program TD block related counters
uint32_t ProgramTdCntrs(uint32_t tdRegIdx, uint32_t* regAddr, uint32_t* regVal, uint32_t blkId,
uint32_t blkCntrIdx);
// Build counter selection register, return how many registers are built
uint32_t BuildCounterSelRegister(uint32_t cntrIdx, uint32_t* regAddr, uint32_t* regVal,
uint32_t blkId, pm4_profile::Counter* blkCntr);
// Build counter selection register, return how many registers are built
uint32_t BuildCounterReadRegisters(uint32_t reg_index, uint32_t block_id, uint32_t* reg_addr,
uint32_t* reg_val);
private:
// Delete counter blocks in the PMU
hsa_status_t RemoveCounterBlocks();
private:
// This contains the available counter groups.
ViCounterBlockMap blk_map_;
// This stores the current profiling state.
rocr_pmu_state_t profiler_state_;
pm4_profile::ParameterSet* parameter_set_;
pm4_profile::InfoSet* info_set_;
int error_code_;
// A flag to indicate the current packet is for copy register value
#define COPY_DATA_FLAG 0xFFFFFFFF
#define MAX_REG_NUM 100
// Pointer used to store counter block list internally
uint32_t blk_list_size_;
pm4_profile::CounterBlock** blk_list_;
// Indicates the number of Shader Engines Present
uint32_t num_se_;
// Used to reset GRBM to its default state
uint32_t reset_grbm_;
};
}
#endif
@@ -8,9 +8,7 @@ set ( LIB_SRC ${LIB_SRC} gfx9_thread_trace.cpp )
#
# Header files include path(s).
#
include_directories ( $ENV{ROCR_INC_DIR} )
include_directories ( ${PROJ_DIR}/commandwriter )
include_directories ( ${HSA_RUNTIME_OSC_DIR} )
#
# Build ThreadTrace as a Static Library object
@@ -1,11 +1,3 @@
#include <iostream>
#include <fstream>
#include <iomanip>
#include <random>
#include <memory>
#include "core/util/os.h"
#include "gfx8_thread_trace.h"
/// @brief Returns the lower 32-bits of a value
@@ -68,14 +60,14 @@ void Gfx8ThreadTrace::InitThreadTraceCfgRegs() {
ttCfgRegs_.ttRegMask.u32All = 0;
ttCfgRegs_.ttRegMask.bits.SH_SEL = 0x0;
ttCfgRegs_.ttRegMask.bits.SIMD_EN = 0xF;
ttCfgRegs_.ttRegMask.bits.CU_SEL = SetCuId();
ttCfgRegs_.ttRegMask.bits.CU_SEL = GetCuId();
ttCfgRegs_.ttRegMask.bits.SQ_STALL_EN__CI__VI = 0x1;
ttCfgRegs_.ttRegMask.bits.SPI_STALL_EN__CI__VI = 0x1;
ttCfgRegs_.ttRegMask.bits.REG_STALL_EN__CI__VI = 0x1;
ttCfgRegs_.ttRegMask.bits.VM_ID_MASK = SetVmId();
ttCfgRegs_.ttRegMask.bits.VM_ID_MASK = GetVmId();
// Override Mask value if a user value is available
uint32_t ttMask = SetMask();
uint32_t ttMask = GetMask();
if (ttMask) {
ttCfgRegs_.ttRegMask.u32All = ttMask;
}
@@ -93,7 +85,7 @@ void Gfx8ThreadTrace::InitThreadTraceCfgRegs() {
ttCfgRegs_.ttRegTokenMask.bits.REG_DROP_ON_STALL__CI__VI = 0x1;
// Override TokenMask1 value if a user value is available
uint32_t tokenMask1 = SetTokenMask();
uint32_t tokenMask1 = GetTokenMask();
if (tokenMask1) {
ttCfgRegs_.ttRegTokenMask.u32All = tokenMask1;
}
@@ -105,7 +97,7 @@ void Gfx8ThreadTrace::InitThreadTraceCfgRegs() {
ttCfgRegs_.ttRegTokenMask2.bits.INST_MASK = 0xFFFFFF7F;
// Override TokenMask2 value if a user value is available
uint32_t tokenMask2 = SetTokenMask2();
uint32_t tokenMask2 = GetTokenMask2();
if (tokenMask2) {
ttCfgRegs_.ttRegTokenMask2.u32All = tokenMask2;
}
@@ -7,8 +7,6 @@
#include "gfxip/gfx8/si_pm4defs.h"
#include "thread_trace.h"
#include <string>
namespace pm4_profile {
typedef struct Gfx8ThreadTraceCfgRegs {
@@ -1,11 +1,3 @@
#include <iostream>
#include <fstream>
#include <iomanip>
#include <random>
#include <memory>
#include "core/util/os.h"
#include "gfx9_thread_trace.h"
/// @brief Returns the lower 32-bits of a value
@@ -68,14 +60,14 @@ void Gfx9ThreadTrace::InitThreadTraceCfgRegs() {
ttCfgRegs_.ttRegMask.u32All = 0;
ttCfgRegs_.ttRegMask.bits.SH_SEL = 0x0;
ttCfgRegs_.ttRegMask.bits.SIMD_EN = 0xF;
ttCfgRegs_.ttRegMask.bits.CU_SEL = SetCuId();
ttCfgRegs_.ttRegMask.bits.CU_SEL = GetCuId();
ttCfgRegs_.ttRegMask.bits.SQ_STALL_EN = 0x1;
ttCfgRegs_.ttRegMask.bits.SPI_STALL_EN = 0x1;
ttCfgRegs_.ttRegMask.bits.REG_STALL_EN = 0x1;
ttCfgRegs_.ttRegMask.bits.VM_ID_MASK = SetVmId();
ttCfgRegs_.ttRegMask.bits.VM_ID_MASK = GetVmId();
// Override Mask value if a user value is available
uint32_t ttMask = SetMask();
uint32_t ttMask = GetMask();
if (ttMask) {
ttCfgRegs_.ttRegMask.u32All = ttMask;
}
@@ -93,7 +85,7 @@ void Gfx9ThreadTrace::InitThreadTraceCfgRegs() {
ttCfgRegs_.ttRegTokenMask.bits.REG_DROP_ON_STALL = 0x1;
// Override TokenMask1 value if a user value is available
uint32_t tokenMask1 = SetTokenMask();
uint32_t tokenMask1 = GetTokenMask();
if (tokenMask1) {
ttCfgRegs_.ttRegTokenMask.u32All = tokenMask1;
}
@@ -105,7 +97,7 @@ void Gfx9ThreadTrace::InitThreadTraceCfgRegs() {
ttCfgRegs_.ttRegTokenMask2.bits.INST_MASK = 0xFFFFFF7F;
// Override TokenMask2 value if a user value is available
uint32_t tokenMask2 = SetTokenMask2();
uint32_t tokenMask2 = GetTokenMask2();
if (tokenMask2) {
ttCfgRegs_.ttRegTokenMask2.u32All = tokenMask2;
}
@@ -1,6 +1,5 @@
#include <iostream>
#include <assert.h>
#include "core/util/os.h"
#include "thread_trace.h"
namespace pm4_profile {
@@ -24,81 +23,36 @@ void ThreadTrace::InitThreadTraceConfig(ThreadTraceConfig* config) const {
config->threadTraceTokenMask2 = 0;
}
uint8_t ThreadTrace::SetCuId() {
uint8_t ThreadTrace::GetCuId() {
uint32_t cuId = ttConfig_.threadTraceTargetCu;
// Allow users to specify the CU to choose for Target tokens
std::string var = os::GetEnvVar("HSA_THREAD_TRACE_SELECT_CU");
if (var.length() > 0) {
cuId = std::stol(var, nullptr, 16);
std::cout << "Using " << cuId << " as CUID for Thread Trace" << std::endl;
}
assert((cuId <= 15) && "Cu Id must be between 0 and 15");
return cuId;
}
uint8_t ThreadTrace::SetVmId() {
uint8_t ThreadTrace::GetVmId() {
uint32_t vmId = ttConfig_.threadTraceVmIdMask;
// Allow users to specify the VMID to choose for Target tokens
std::string var = os::GetEnvVar("HSA_THREAD_TRACE_SELECT_VMID");
if (var.length() > 0) {
vmId = std::stol(var, nullptr, 16);
std::cout << "Using " << vmId << " as VMID for Thread Trace" << std::endl;
}
assert((vmId <= 2) && "VmId must be between 0 and 2");
return vmId;
}
uint32_t ThreadTrace::SetMask() {
uint32_t ThreadTrace::GetMask() {
uint32_t ttMask = ttConfig_.threadTraceMask;
const uint32_t validMask = 0x00C0D0;
// Allow users to specify the Mask to choose for configuration parameters
std::string var = os::GetEnvVar("HSA_THREAD_TRACE_SELECT_MASK");
if (var.length() > 0) {
ttMask = std::stol(var, nullptr, 16);
std::cout << "Using " << ttMask << " as Mask for Thread Trace" << std::endl;
}
assert(((ttMask & validMask) == 0) && "Mask should have bits [4,6,7] set to Zero");
return ttMask;
}
uint32_t ThreadTrace::SetTokenMask() {
uint32_t ThreadTrace::GetTokenMask() {
uint32_t tokenMask = ttConfig_.threadTraceTokenMask;
const uint32_t validMask = 0xFF000000;
// Allow users to specify the TokenMask to choose for Target tokens
std::string var = os::GetEnvVar("HSA_THREAD_TRACE_SELECT_TOKEN_MASK1");
if (var.length() > 0) {
tokenMask = std::stol(var, nullptr, 16);
std::cout << "Using " << tokenMask << " as TokenMask for Thread Trace" << std::endl;
}
assert(((tokenMask & validMask) == 0) && "TokenMask should have bits [31:25] set to Zero");
return tokenMask;
}
uint32_t ThreadTrace::SetTokenMask2() {
uint32_t ThreadTrace::GetTokenMask2() {
uint32_t tokenMask2 = ttConfig_.threadTraceTokenMask2;
const uint32_t validMask = 0xFFFF0000;
// Allow users to specify the TokenMask2 to choose for Target tokens
std::string var = os::GetEnvVar("HSA_THREAD_TRACE_SELECT_TOKEN_MASK2");
if (var.length() > 0) {
tokenMask2 = std::stol(var, nullptr, 16);
std::cout << "Using " << tokenMask2 << " as TokenMask2 for Thread Trace" << std::endl;
}
assert(((tokenMask2 & validMask) == 0) && "TokenMask2 should have bits [31:16] set to Zero");
return tokenMask2;
}
@@ -7,18 +7,11 @@
// Move them as static variables later on
#define TT_WRITE_PTR_MASK (0x3FFFFFFF)
#define TT_DEFAULT_BUFF_SIZE_SCALE (16)
#define TT_DEFAULT_BUFF_SIZE (1024 * 1024 * 8)
// Size of block in bytesper increment in WPTR
#define TT_WRITE_PTR_BLK (32)
// Factor by which to shift buffer address
#define TT_BUFF_ALIGN_SHIFT (12)
// Align address to 64 Kilobytes
#define TT_BUFF_ADDR_ALIGN (0x10000)
namespace pm4_profile {
// ThreadTrace config
@@ -43,19 +36,19 @@ class ThreadTrace {
virtual ~ThreadTrace(){};
// Obtain the CU id to use for thread tracing
uint8_t SetCuId();
uint8_t GetCuId();
// Obtain the VM id to use for thread tracing
uint8_t SetVmId();
uint8_t GetVmId();
// Obtain the Mask to use for thread tracing
uint32_t SetMask();
uint32_t GetMask();
// Obtain the Token Mask 1 to use for thread tracing
uint32_t SetTokenMask();
uint32_t GetTokenMask();
// Obtain the Token Mask 2 to use for thread tracing
uint32_t SetTokenMask2();
uint32_t GetTokenMask2();
// Initializes various data structures and handles that
// are needed to support a thread trace session
@@ -3,10 +3,8 @@
#
include_directories ( $ENV{ROCR_INC_DIR} )
include_directories ( ${API_DIR} )
include_directories ( ${PROJ_DIR}/aqlprofile )
include_directories ( ${TEST_DIR}/common )
include_directories ( ${TEST_DIR}/util )
include_directories ( ${TEST_DIR}/ctrl )
include_directories ( ${CORE_UTIL_DIR} )
#
# Specify the directory containing the libraries of HsaRt
@@ -19,8 +17,8 @@ find_library ( ROCR_LIB NAMES hsa-runtime64 PATHS $ENV{ROCR_LIB_DIR} )
# Set Name for Common library and build it as a
# static library to be linked with others
#
set ( COMMON_LIB "common${ONLY64STR}" )
add_subdirectory ( ${TEST_DIR}/common "${PROJECT_BINARY_DIR}/common" )
set ( UTIL_LIB "util${ONLY64STR}" )
add_subdirectory ( ${TEST_DIR}/util "${PROJECT_BINARY_DIR}/util" )
#
# Build the test library
@@ -39,7 +37,7 @@ set ( TEST_LIBS ${LIB_NAME} )
set ( SRC_LIST ${TEST_DIR}/ctrl/test.cpp )
set ( SRC_LIST ${SRC_LIST} ${TEST_DIR}/ctrl/test_pmgr.cpp )
set ( SRC_LIST ${SRC_LIST} ${TEST_DIR}/ctrl/test_hsa.cpp )
set ( LIB_LIST ${TEST_LIBS} ${COMMON_LIB} ${CORE_UTILS_LIB} ${ROCR_LIB} ${TARGET_LIB} )
set ( LIB_LIST ${TEST_LIBS} ${UTIL_LIB} ${CORE_UTILS_LIB} ${ROCR_LIB} ${TARGET_LIB} )
set ( EXE_NAME "ctrl" )
add_executable ( ${EXE_NAME} ${SRC_LIST} )
target_link_libraries( ${EXE_NAME} ${LIB_LIST} c stdc++ dl pthread rt atomic )
@@ -1,15 +0,0 @@
#
# Source files for Rocr Utils library
#
file( GLOB MODULE_SRC "*.cpp" )
#
# Header files include path(s).
#
include_directories ( $ENV{ROCR_INC_DIR} )
#
# Build Utils as a Static Library object
#
add_library( ${COMMON_LIB} STATIC ${MODULE_SRC} )
target_link_libraries( ${COMMON_LIB} c stdc++ dl pthread rt )
@@ -1,45 +0,0 @@
#include "common.hpp"
void ErrorCheck(hsa_status_t hsa_error_code) {
if (hsa_error_code != HSA_STATUS_SUCCESS) {
std::cerr << "HSA reported error!" << std::endl;
exit(EXIT_FAILURE);
}
}
hsa_status_t FindGpuDevice(hsa_agent_t agent, void* data) {
if (data == NULL) {
return HSA_STATUS_ERROR_INVALID_ARGUMENT;
}
hsa_device_type_t hsa_device_type;
hsa_status_t hsa_error_code = hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &hsa_device_type);
if (hsa_error_code != HSA_STATUS_SUCCESS) {
return hsa_error_code;
}
if (hsa_device_type == HSA_DEVICE_TYPE_GPU) {
*((hsa_agent_t*)data) = agent;
}
return HSA_STATUS_SUCCESS;
}
hsa_status_t FindHostRegion(hsa_region_t region, void* data) {
if (data == NULL) {
return HSA_STATUS_ERROR_INVALID_ARGUMENT;
}
bool is_host_region = false;
hsa_status_t hsa_error_code = hsa_region_get_info(
region, (hsa_region_info_t)HSA_AMD_REGION_INFO_HOST_ACCESSIBLE, &is_host_region);
if (hsa_error_code != HSA_STATUS_SUCCESS) {
return hsa_error_code;
}
if (is_host_region) {
*((hsa_region_t*)data) = region;
}
return HSA_STATUS_SUCCESS;
}
@@ -1,27 +0,0 @@
#ifndef COMMON_COMMON_HPP
#define COMMON_COMMON_HPP
#include <cstdlib>
#include <iostream>
#include "hsa.h"
#include "hsa_ext_finalize.h"
#include "hsa_ext_amd.h"
#if defined(_MSC_VER)
#define ALIGNED_(x) __declspec(align(x))
#else
#if defined(__GNUC__)
#define ALIGNED_(x) __attribute__((aligned(x)))
#endif // __GNUC__
#endif // _MSC_VER
#define MULTILINE(...) #__VA_ARGS__
void ErrorCheck(hsa_status_t hsa_error_code);
hsa_status_t FindGpuDevice(hsa_agent_t agent, void* data);
hsa_status_t FindHostRegion(hsa_region_t region, void* data);
#endif // COMMON_COMMON_HPP
@@ -1,155 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <cassert>
#include <iostream>
#include <vector>
#include <string>
#include "hsa.h"
#include "hsa_ext_profiler.h"
#include "amd_hsa_tools_interfaces.h"
#include "hsa_perf_cntrs.hpp"
using namespace std;
void PreDispatchCallback(const hsa_dispatch_callback_t* dispParam, void* usrArg) {
assert((dispParam->pre_dispatch) && "Pre Dispatch Callback Param is Malformed");
hsa_ext_tools_pmu_t* perfMgr = reinterpret_cast<hsa_ext_tools_pmu_t*>(usrArg);
hsa_status_t status =
hsa_ext_tools_pmu_begin(*perfMgr, dispParam->queue, dispParam->aql_translation_handle, true);
assert((status == HSA_STATUS_SUCCESS) && "Error in beginning Perf Cntr Session");
}
void PostDispatchCallback(const hsa_dispatch_callback_t* dispParam, void* usrArg) {
assert((!dispParam->pre_dispatch) && "Post Dispatch Callback Param is Malformed");
hsa_ext_tools_pmu_t* perfMgr = reinterpret_cast<hsa_ext_tools_pmu_t*>(usrArg);
hsa_status_t status =
hsa_ext_tools_pmu_end(*perfMgr, dispParam->queue, dispParam->aql_translation_handle);
assert((status == HSA_STATUS_SUCCESS) && "Error in endning Perf Cntr Session");
}
// Constructor of the class
RocrPerfCntrApp::RocrPerfCntrApp() : perfMgr_(NULL) {}
// Destructor of the class. Ideally it should delete the
// PMU and its counters
RocrPerfCntrApp::~RocrPerfCntrApp() {}
// Return the number of perf counters
uint32_t RocrPerfCntrApp::GetNumPerfCntrs() { return uint32_t(cntrList_.size()); }
// Return the handle of perf counter at specified index
CntrInfo* RocrPerfCntrApp::GetPerfCntr(uint32_t idx) { return cntrList_[idx]; }
// Print the various fields of Perf Cntrs being programmed
bool RocrPerfCntrApp::PrintCntrs() {
CntrInfo* info;
int size = uint32_t(cntrList_.size());
for (int idx = 0; idx < size; idx++) {
info = cntrList_[idx];
std::cout << std::endl;
std::cout << "Rocr Perf Cntr Id: " << info->cntrId << std::endl;
std::cout << "Rocr Perf Cntr Name: " << info->cntrName << std::endl;
std::cout << "Rocr Perf Cntr Blk Id: " << info->blkId << std::endl;
std::cout << "Rocr Perf Cntr Value: " << info->cntrResult << std::endl;
std::cout << "Rocr Perf Cntr Validation: " << info->cnfType << std::endl;
std::cout << std::endl;
}
return true;
}
// Initialize the list of perf counters
// block id of kHsaAiCounterBlockSQ = 14 == 0x0E
hsa_status_t RocrPerfCntrApp::Init(hsa_agent_t agent) {
// Initialize the list of Perf Cntrs
// Add SQ counter for number of waves
CntrInfo* info = NULL;
cntrList_.reserve(23);
// Event for number of Waves
info = new CntrInfo(0x4, "SQ_SQ_PERF_SEL_WAVES", NULL, 0x0E, NULL, 0x00, 0xFFFFFFFF,
CntrValCnf_Exact);
cntrList_.push_back(info);
// Event for number of Threads
info = new CntrInfo(0xE, "SQ_SQ_PERF_SEL_ITEMS", NULL, 0x0E, NULL, 0x00, 0xFFFFFFFF,
CntrValCnf_Exact);
cntrList_.push_back(info);
// Create an instance of Perf Mgr
hsa_status_t status;
status = hsa_ext_tools_create_pmu(agent, &perfMgr_);
assert((status == HSA_STATUS_SUCCESS) && "Error in creating Perf Cntr Mgr");
// Process each counter from the list as necessary
// each counter descriptor with its perf block handle
// and create an instance of counter in that block
uint32_t size = GetNumPerfCntrs();
for (uint32_t idx = 0; idx < size; idx++) {
info = GetPerfCntr(idx);
// Obtain the handle of perf block
if (info->blkHndl == NULL) {
status = hsa_ext_tools_get_counter_block_by_id(perfMgr_, info->blkId, &info->blkHndl);
assert((status == HSA_STATUS_SUCCESS) && "Error in getting Perf Cntr Blk Hndl");
}
// Create an instance of counter in the perf block
status = hsa_ext_tools_create_counter(info->blkHndl, &info->cntrHndl);
assert((status == HSA_STATUS_SUCCESS) && "Error in creating Perf Cntr in Perf Blk");
// Update the Event Index property of counter
uint32_t cntrProp = HSA_EXT_TOOLS_COUNTER_PARAMETER_EVENT_INDEX;
status = hsa_ext_tools_set_counter_parameter(info->cntrHndl, cntrProp, sizeof(uint32_t),
(void*)&info->cntrId);
assert((status == HSA_STATUS_SUCCESS) && "Error in updating Perf Cntr Property Event Index");
// Enable the updated perf counter
status = hsa_ext_tools_set_counter_enabled(info->cntrHndl, true);
assert((status == HSA_STATUS_SUCCESS) && "Error in enabing Perf Cntr");
}
return status;
}
// Register Pre and Post dispatch callbacks
void RocrPerfCntrApp::RegisterCallbacks(hsa_queue_t* queue) {
hsa_status_t status;
status = hsa_ext_tools_set_callback_functions(queue, PreDispatchCallback, PostDispatchCallback);
assert((status == HSA_STATUS_SUCCESS) && "Error in registering Pre & Post Dispatch Callbacks");
status = hsa_ext_tools_set_callback_arguments(queue, &perfMgr_, &perfMgr_);
assert((status == HSA_STATUS_SUCCESS) &&
"Error in registering Pre & Post Dispatch Callback Params");
return;
}
// Wait for perf counter collection to complete
hsa_status_t RocrPerfCntrApp::Wait() {
hsa_status_t status;
status = hsa_ext_tools_pmu_wait_for_completion(perfMgr_, 5000);
assert((status == HSA_STATUS_SUCCESS) && "Error in Waiting for Perf Cntr Completion");
return status;
}
// Validate perf counter values
hsa_status_t RocrPerfCntrApp::Validate() {
// Retrieve the results of the different Perf Cntrs
// and validate them as configured
CntrInfo* info = NULL;
hsa_status_t status = HSA_STATUS_SUCCESS;
uint32_t size = GetNumPerfCntrs();
for (uint32_t idx = 0; idx < size; idx++) {
info = GetPerfCntr(idx);
status = hsa_ext_tools_get_counter_result(info->cntrHndl, &info->cntrResult);
std::cout << "Value of Perf Cntr is: " << info->cntrResult << std::endl;
}
return status;
}
@@ -1,110 +0,0 @@
#ifndef ROCR_PERF_CNTR_APP_H_
#define ROCR_PERF_CNTR_APP_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <string>
#include "hsa.h"
#include "hsa_ext_profiler.h"
typedef enum CntrValCnfType {
///< no counter value validation should be performed
CntrValCnf_None,
///< counter value should be an exact match to expectedResult
CntrValCnf_Exact,
///< counter value should be greater than expectedResult
CntrValCnf_GreaterThan,
///< counter value should be less than expectedResult
CntrValCnf_LessThan
} CntrValCnfType;
/// Struct used to encapsulate Counter Info
typedef struct CntrInfo {
///< Id of counter in hardware block
uint32_t cntrId;
///< Name of counter
char cntrName[72];
///< Handle of perf counter
hsa_ext_tools_counter_t cntrHndl;
///< Id of hardware block containing the counter
uint32_t blkId;
///< Handle of counter block
hsa_ext_tools_counter_block_t blkHndl;
///< Expected value of perf counte
uint64_t expectedResult;
///< Value of perf counter expected
uint64_t cntrResult;
///< Type of validation upon completion of dispatch
CntrValCnfType cnfType;
CntrInfo(uint32_t cntrId, char* cntrName, void* cntrHndl, uint32_t blkId, void* blkHndl,
uint64_t expResult, uint64_t result, CntrValCnfType cnfType) {
this->cntrId = cntrId;
this->cntrHndl = cntrHndl;
this->blkId = blkId;
this->blkHndl = blkHndl;
this->expectedResult = expResult;
this->cntrResult = result;
this->cnfType = cnfType;
memcpy(this->cntrName, cntrName, strlen(cntrName));
}
} CntrInfo;
class RocrPerfCntrApp {
public:
// Constructor of the class. Will initialize the list of perf counters
// that will be used to program the device
RocrPerfCntrApp();
// Destructor of the class
~RocrPerfCntrApp();
// Return the number of perf counters
uint32_t GetNumPerfCntrs();
// Return the handle of perf counter at specified index
CntrInfo* GetPerfCntr(uint32_t idx);
// Print the list of perf counters
bool PrintCntrs();
// Initialize the list of perf counters
hsa_status_t Init(hsa_agent_t agent);
// Register Pre and Post dispatch callbacks
void RegisterCallbacks(hsa_queue_t* queue);
// Wait for perf counter collection to complete
hsa_status_t Wait();
// Validate perf counter values
hsa_status_t Validate();
private:
// Number of queues to create
std::vector<CntrInfo*> cntrList_;
// Handle of Perf Cntr Manager
hsa_ext_tools_pmu_t perfMgr_;
};
#endif // ROCR_PERF_CNTR_APP_H_
@@ -29,7 +29,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
#define _TESTAQL_H_
#include "hsa.h"
#include "hsa_rsrc_factory.hpp"
#include "hsa_rsrc_factory.h"
#include "hsa_ext_amd_aql_profile.h"
#define test_assert(cond) \
@@ -25,9 +25,12 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "os.h"
#include "helper_funcs.hpp"
#include "hsa_rsrc_factory.hpp"
#include <assert.h>
#include <atomic>
//#include "os.h"
#include "helper_funcs.h"
#include "hsa_rsrc_factory.h"
#include "test_hsa.h"
bool TestHSA::initialize(int arg_cnt, char** arg_list) {
@@ -146,7 +149,6 @@ bool TestHSA::run() {
memset(&aql, 0, sizeof(aql));
// Set the packet's type, barrier bit, acquire and release fences
aql.header = HSA_PACKET_TYPE_KERNEL_DISPATCH;
aql.header |= 1ul << HSA_PACKET_HEADER_BARRIER;
aql.header |= HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_SCACQUIRE_FENCE_SCOPE;
aql.header |= HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_SCRELEASE_FENCE_SCOPE;
// Populate Aql packet with default values
@@ -30,7 +30,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
#include "test_aql.h"
#include "test_kernel.h"
#include "hsa_rsrc_factory.hpp"
#include "hsa_rsrc_factory.h"
// Class implements HSA test
class TestHSA : public TestAql {
@@ -58,9 +58,8 @@ bool TestPMgr::addPacketGfx9(const packet_t* packet) {
}
bool TestPMgr::addPacketGfx8(const packet_t* packet) {
// Create Legacy PM4 data
const hsa_ext_amd_aql_pm4_packet_t * aql_packet =
(const hsa_ext_amd_aql_pm4_packet_t *) packet;
// Create legacy devices PM4 data
const hsa_ext_amd_aql_pm4_packet_t* aql_packet = (const hsa_ext_amd_aql_pm4_packet_t*)packet;
slot_pm4_s data;
hsa_ext_amd_aql_profile_legacy_get_pm4(aql_packet, (void*)data.words);
@@ -70,7 +69,7 @@ bool TestPMgr::addPacketGfx8(const packet_t* packet) {
// Copy Aql packet into queue buffer
packet_t* ptr = ((packet_t*)(getQueue()->base_address)) + (que_idx & mask);
slot_pm4_t * slot_pm4 = (slot_pm4_t*)ptr;
slot_pm4_t* slot_pm4 = (slot_pm4_t*)ptr;
slot_pm4->store(data, std::memory_order_relaxed);
// Increment the write index and ring the doorbell to dispatch the kernel.
@@ -81,10 +80,8 @@ bool TestPMgr::addPacketGfx8(const packet_t* packet) {
}
bool TestPMgr::addPacket(const packet_t* packet) {
const char * agent_name = getAgentInfo()->name;
return (strncmp(agent_name, "gfx8", 4) == 0) ?
addPacketGfx8(packet) :
addPacketGfx9(packet);
const char* agent_name = getAgentInfo()->name;
return (strncmp(agent_name, "gfx8", 4) == 0) ? addPacketGfx8(packet) : addPacketGfx9(packet);
}
bool TestPMgr::run() {
@@ -31,12 +31,11 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
#include <atomic>
#include "test_aql.h"
#include "amd_aql_pm4_ib_packet.h"
// SimpleConvolution: Class implements OpenCL SimpleConvolution sample
class TestPMgr : public TestAql {
public:
typedef amd_aql_pm4_ib_packet_t packet_t;
typedef hsa_ext_amd_aql_pm4_packet_t packet_t;
TestPMgr(TestAql* t);
bool run();
@@ -53,7 +52,7 @@ class TestPMgr : public TestAql {
private:
enum {
SLOT_PM4_SIZE_DW = HSA_EXT_AQL_PROFILE_LEGACY_PM4_PACKET_SIZE / sizeof(uint32_t),
SLOT_PM4_SIZE_AQLP = HSA_EXT_AQL_PROFILE_LEGACY_PM4_PACKET_SIZE / 64
SLOT_PM4_SIZE_AQLP = HSA_EXT_AQL_PROFILE_LEGACY_PM4_PACKET_SIZE / sizeof(packet_t)
};
struct slot_pm4_s {
uint32_t words[SLOT_PM4_SIZE_DW];
@@ -25,7 +25,10 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "helper_funcs.hpp"
#include <iostream>
#include <string.h>
#include "helper_funcs.h"
#include "simple_convolution.h"
SimpleConvolution::SimpleConvolution() {
@@ -1,14 +1,12 @@
#
# Source files for Rocr Utils library
#
set ( MODULE_SRC ${CORE_UTIL_DIR}/lnx/os_linux.cpp )
file( GLOB MODULE_SRC "*.cpp" )
#
# Header files include path(s).
#
include_directories ( $ENV{ROCR_INC_DIR} )
include_directories ( ${HSA_RUNTIME_OSC_DIR} )
include_directories ( ${CORE_UTIL_DIR} )
#
# Build Utils as a Static Library object
@@ -22,12 +22,19 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
POSSIBILITY OF SUCH DAMAGE.
********************************************************************/
#include "helper_funcs.hpp"
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
#include <time.h>
#include "helper_funcs.h"
#ifndef _WIN32
#include <unistd.h>
#endif
void error(std::string errorMsg) { std::cout << "Error: " << errorMsg << std::endl; }
/*
* Prints no more than 256 elements of the given array.
@@ -47,11 +54,11 @@ void printArray(const std::string header, const T* data, const int width, const
}
template <typename T>
int fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin, const T rangeMax,
unsigned int seed) {
bool fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin, const T rangeMax,
unsigned int seed) {
if (!arrayPtr) {
error("Cannot fill array. NULL pointer.");
return HSA_SDK_FAILURE;
return false;
}
if (!seed) seed = (unsigned int)time(NULL);
@@ -66,13 +73,13 @@ int fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin,
arrayPtr[index] = rangeMin + T(range * rand() / (RAND_MAX + 1.0));
}
return HSA_SDK_SUCCESS;
return true;
}
template <typename T> int fillPos(T* arrayPtr, const int width, const int height) {
template <typename T> bool fillPos(T* arrayPtr, const int width, const int height) {
if (!arrayPtr) {
error("Cannot fill array. NULL pointer.");
return HSA_SDK_FAILURE;
return false;
}
/* initialisation of input with positions*/
@@ -82,14 +89,14 @@ template <typename T> int fillPos(T* arrayPtr, const int width, const int height
arrayPtr[index] = index;
}
return HSA_SDK_SUCCESS;
return true;
}
template <typename T>
int fillConstant(T* arrayPtr, const int width, const int height, const T val) {
bool fillConstant(T* arrayPtr, const int width, const int height, const T val) {
if (!arrayPtr) {
error("Cannot fill array. NULL pointer.");
return HSA_SDK_FAILURE;
return false;
}
/* initialisation of input with constant value*/
@@ -99,7 +106,7 @@ int fillConstant(T* arrayPtr, const int width, const int height, const T val) {
arrayPtr[index] = val;
}
return HSA_SDK_SUCCESS;
return true;
}
template <typename T> T roundToPowerOf2(T val) {
@@ -112,32 +119,17 @@ template <typename T> T roundToPowerOf2(T val) {
return val;
}
template <typename T> int isPowerOf2(T val) {
template <typename T> bool isPowerOf2(T val) {
long long _val = val;
if ((_val & (-_val)) - _val == 0 && _val != 0)
return HSA_SDK_SUCCESS;
else
return HSA_SDK_FAILURE;
return (((_val & (-_val)) - _val == 0) && (_val != 0));
}
template <typename T> bool checkVal(T input, T reference, std::string message, bool isAPIerror) {
if (input == reference) {
return true;
} else {
error(message);
return false;
}
}
template <typename T> std::string toString(T t, std::ios_base& (*r)(std::ios_base&)) {
std::ostringstream output;
output << r << t;
return output.str();
}
bool compare(const float* refData, const float* data, const int length, const float epsilon) {
float error = 0.0f;
float ref = 0.0f;
@@ -178,19 +170,6 @@ bool compare(const double* refData, const double* data, const int length, const
return error < epsilon;
}
void error(const char* errorMsg) { std::cout << "Error: " << errorMsg << std::endl; }
void error(std::string errorMsg) { std::cout << "Error: " << errorMsg << std::endl; }
void expectedError(const char* errorMsg) {
std::cout << "Expected Error: " << errorMsg << std::endl;
}
void expectedError(std::string errorMsg) {
std::cout << "Expected Error: " << errorMsg << std::endl;
}
/////////////////////////////////////////////////////////////////
// Template Instantiations
/////////////////////////////////////////////////////////////////
@@ -202,56 +181,45 @@ template void printArray<long>(const std::string, const long*, int, int);
template void printArray<float>(const std::string, const float*, int, int);
template void printArray<double>(const std::string, const double*, int, int);
template int fillRandom<unsigned char>(unsigned char* arrayPtr, const int width, const int height,
unsigned char rangeMin, unsigned char rangeMax,
template bool fillRandom<unsigned char>(unsigned char* arrayPtr, const int width, const int height,
unsigned char rangeMin, unsigned char rangeMax,
unsigned int seed);
template bool fillRandom<unsigned int>(unsigned int* arrayPtr, const int width, const int height,
unsigned int rangeMin, unsigned int rangeMax,
unsigned int seed);
template int fillRandom<unsigned int>(unsigned int* arrayPtr, const int width, const int height,
unsigned int rangeMin, unsigned int rangeMax,
unsigned int seed);
template int fillRandom<int>(int* arrayPtr, const int width, const int height, int rangeMin,
int rangeMax, unsigned int seed);
template int fillRandom<long>(long* arrayPtr, const int width, const int height, long rangeMin,
long rangeMax, unsigned int seed);
template int fillRandom<float>(float* arrayPtr, const int width, const int height, float rangeMin,
float rangeMax, unsigned int seed);
template int fillRandom<double>(double* arrayPtr, const int width, const int height,
double rangeMin, double rangeMax, unsigned int seed);
template bool fillRandom<int>(int* arrayPtr, const int width, const int height, int rangeMin,
int rangeMax, unsigned int seed);
template bool fillRandom<long>(long* arrayPtr, const int width, const int height, long rangeMin,
long rangeMax, unsigned int seed);
template bool fillRandom<float>(float* arrayPtr, const int width, const int height, float rangeMin,
float rangeMax, unsigned int seed);
template bool fillRandom<double>(double* arrayPtr, const int width, const int height,
double rangeMin, double rangeMax, unsigned int seed);
template short roundToPowerOf2<short>(short val);
template unsigned int roundToPowerOf2<unsigned int>(unsigned int val);
template int roundToPowerOf2<int>(int val);
template long roundToPowerOf2<long>(long val);
template int isPowerOf2<short>(short val);
template int isPowerOf2<unsigned int>(unsigned int val);
template int isPowerOf2<int>(int val);
template int isPowerOf2<long>(long val);
template bool isPowerOf2<short>(short val);
template bool isPowerOf2<unsigned int>(unsigned int val);
template bool isPowerOf2<int>(int val);
template bool isPowerOf2<long>(long val);
template <> int fillPos<short>(short* arrayPtr, const int width, const int height);
template <> int fillPos<unsigned int>(unsigned int* arrayPtr, const int width, const int height);
template <> int fillPos<int>(int* arrayPtr, const int width, const int height);
template <> int fillPos<long>(long* arrayPtr, const int width, const int height);
template <> bool fillPos<short>(short* arrayPtr, const int width, const int height);
template <> bool fillPos<unsigned int>(unsigned int* arrayPtr, const int width, const int height);
template <> bool fillPos<int>(int* arrayPtr, const int width, const int height);
template <> bool fillPos<long>(long* arrayPtr, const int width, const int height);
template <>
int fillConstant<short>(short* arrayPtr, const int width, const int height, const short val);
bool fillConstant<short>(short* arrayPtr, const int width, const int height, const short val);
template <>
int fillConstant(unsigned int* arrayPtr, const int width, const int height, const unsigned int val);
template <> int fillConstant(int* arrayPtr, const int width, const int height, const int val);
template <> int fillConstant(long* arrayPtr, const int width, const int height, const long val);
template <> int fillConstant(long* arrayPtr, const int width, const int height, const long val);
template <> int fillConstant(long* arrayPtr, const int width, const int height, const long val);
template bool checkVal<char>(char input, char reference, std::string message, bool isAPIerror);
template bool checkVal<bool>(bool input, bool reference, std::string message, bool isAPIerror);
template bool checkVal<std::string>(std::string input, std::string reference, std::string message,
bool isAPIerror);
template bool checkVal<short>(short input, short reference, std::string message, bool isAPIerror);
template bool checkVal<unsigned int>(unsigned int input, unsigned int reference,
std::string message, bool isAPIerror);
template bool checkVal<int>(int input, int reference, std::string message, bool isAPIerror);
template bool checkVal<long>(long input, long reference, std::string message, bool isAPIerror);
bool fillConstant(unsigned int* arrayPtr, const int width, const int height,
const unsigned int val);
template <> bool fillConstant(int* arrayPtr, const int width, const int height, const int val);
template <> bool fillConstant(long* arrayPtr, const int width, const int height, const long val);
template <> bool fillConstant(long* arrayPtr, const int width, const int height, const long val);
template <> bool fillConstant(long* arrayPtr, const int width, const int height, const long val);
template std::string toString<char>(char t, std::ios_base& (*r)(std::ios_base&));
template std::string toString<short>(short t, std::ios_base& (*r)(std::ios_base&));
@@ -21,53 +21,10 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
********************************************************************/
#ifndef HELPER_FUNCS_HPP_
#define HELPER_FUNCS_HPP_
#ifndef _HELPER_FUNCS_H_
#define _HELPER_FUNCS_H_
#define HSA_SDK_SUCCESS 0
#define HSA_SDK_FAILURE 1
#define HSA_SDK_EXPECTED_FAILURE 2
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>
#include <ctime>
#include <cmath>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <malloc.h>
/**
* error
* constant function, Prints error messages
* @param errorMsg char* message
*/
void error(const char* errorMsg);
/**
* error
* constant function, Prints error messages
* @param errorMsg std::string message
*/
void error(std::string errorMsg);
/**
* expectedError
* constant function, Prints error messages
* @param errorMsg char* message
*/
void expectedError(const char* errorMsg);
/**
* expectedError
* constant function, Prints error messages
* @param errorMsg string message
*/
void expectedError(std::string errorMsg);
/**
* compare template version
@@ -95,20 +52,21 @@ void printArray(const std::string header, const T* data, const int width, const
* fill array with random values
*/
template <typename T>
int fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin, const T rangeMax,
unsigned int seed = 123);
bool fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin, const T rangeMax,
unsigned int seed = 123);
/**
* fillPos
* fill the specified positions
*/
template <typename T> int fillPos(T* arrayPtr, const int width, const int height);
template <typename T> bool fillPos(T* arrayPtr, const int width, const int height);
/**
* fillConstant
* fill the array with constant value
*/
template <typename T> int fillConstant(T* arrayPtr, const int width, const int height, const T val);
template <typename T>
bool fillConstant(T* arrayPtr, const int width, const int height, const T val);
/**
@@ -121,15 +79,7 @@ template <typename T> T roundToPowerOf2(T val);
* isPowerOf2
* checks if input is a power of 2
*/
template <typename T> int isPowerOf2(T val);
/**
* checkVal
* Set default(isAPIerror) parameter to false
* if checkVaul is used to check otherthan OpenCL API error code
*/
template <typename T>
bool checkVal(T input, T reference, std::string message, bool isAPIerror = true);
template <typename T> bool isPowerOf2(T val);
/**
* toString
@@ -137,5 +87,4 @@ bool checkVal(T input, T reference, std::string message, bool isAPIerror = true)
*/
template <typename T> std::string toString(T t, std::ios_base& (*r)(std::ios_base&));
#endif
#endif // _HELPER_FUNCS_H_
@@ -10,12 +10,10 @@
#include <string>
#include "hsa.h"
#include "hsa_rsrc_factory.hpp"
#include "hsa_rsrc_factory.h"
#include "hsa_ext_finalize.h"
#include "hsa_ext_profiler.h"
#include "common.hpp"
using namespace std;
// Provide access to command line arguments passed in by user
@@ -10,7 +10,7 @@
#include <vector>
#include <string>
#include "hsatimer.h"
#include "perf_timer.h"
#include "hsa.h"
#include "hsa_ext_finalize.h"
@@ -1,4 +1,4 @@
#include "hsatimer.h"
#include "perf_timer.h"
PerfTimer::PerfTimer() { freq_in_100mhz = MeasureTSCFreqHz(); }
@@ -30,7 +30,7 @@ int PerfTimer::CreateTimer() {
int PerfTimer::StartTimer(int index) {
if (index >= (int)_timers.size()) {
Error("Cannot reset timer. Invalid handle.");
return HSA_FAILURE;
return FAILURE;
}
#ifdef _WIN32
@@ -41,9 +41,7 @@ int PerfTimer::StartTimer(int index) {
_timers[index]->_start = (double)tmpStart;
#else
// AMD Windows timing method
#endif
#else
// General Linux timing method
#ifndef _AMD
@@ -51,17 +49,13 @@ int PerfTimer::StartTimer(int index) {
gettimeofday(&s, 0);
_timers[index]->_start = s.tv_sec * 1.0E3 + ((double)(s.tv_usec / 1.0E3));
#else
// AMD timing method
unsigned int unused;
_timers[index]->_start = __rdtscp(&unused);
#endif
#endif
#endif
return HSA_SUCCESS;
return SUCCESS;
}
@@ -69,7 +63,7 @@ int PerfTimer::StopTimer(int index) {
double n = 0;
if (index >= (int)_timers.size()) {
Error("Cannot reset timer. Invalid handle.");
return HSA_FAILURE;
return FAILURE;
}
#ifdef _WIN32
#ifndef _AMD
@@ -77,9 +71,7 @@ int PerfTimer::StopTimer(int index) {
QueryPerformanceCounter((LARGE_INTEGER*)&(n1));
n = (double)n1;
#else
// AMD Window Timing
#endif
#else
@@ -90,11 +82,9 @@ int PerfTimer::StopTimer(int index) {
n = s.tv_sec * 1.0E3 + (double)(s.tv_usec / 1.0E3);
#else
// AMD Linux timing
unsigned int unused;
n = __rdtscp(&unused);
#endif
#endif
n -= _timers[index]->_start;
@@ -105,10 +95,9 @@ int PerfTimer::StopTimer(int index) {
#else
//_timers[index]->_clocks += 10 * n /freq_in_100mhz; // unit is ns
_timers[index]->_clocks += 1.0E-6 * 10 * n / freq_in_100mhz; // convert to ms
cout << "_AMD is enabled!!!" << endl;
#endif
return HSA_SUCCESS;
return SUCCESS;
}
void PerfTimer::Error(string str) { cout << str << endl; }
@@ -117,7 +106,7 @@ void PerfTimer::Error(string str) { cout << str << endl; }
double PerfTimer::ReadTimer(int index) {
if (index >= (int)_timers.size()) {
Error("Cannot read timer. Invalid handle.");
return HSA_FAILURE;
return FAILURE;
}
double reading = double(_timers[index]->_clocks);
@@ -1,5 +1,5 @@
#ifndef __MYTIME__
#define __MYTIME__
#ifndef _PERF_TIMER_H_
#define _PERF_TIMER_H_
// Will use AMD timer and general Linux timer based on users' need --> compilation flag
// need to consider platform is Windows or Linux
@@ -11,8 +11,6 @@
#include <iostream>
#include <vector>
#include <string>
using namespace std;
#if defined(_MSC_VER)
#include <time.h>
#include <windows.h>
@@ -24,10 +22,25 @@ using namespace std;
#endif // __GNUC__
#endif //_MSC_VER
#define HSA_FAILURE 1
#define HSA_SUCCESS 0
using namespace std;
class PerfTimer {
public:
enum { SUCCESS = 0, FAILURE = 1 };
PerfTimer();
~PerfTimer();
// General Linux timing method
int CreateTimer();
int StartTimer(int index);
int StopTimer(int index);
// retrieve time
double ReadTimer(int index);
// write into a file
double WriteTimer(int index);
private:
struct Timer {
string name; /* < name name of time object*/
@@ -39,30 +52,11 @@ class PerfTimer {
std::vector<Timer*> _timers; /*< _timers vector to Timer objects */
double freq_in_100mhz;
public:
PerfTimer();
~PerfTimer();
private:
// AMD timing method
uint64_t CoarseTimestampUs();
uint64_t MeasureTSCFreqHz();
// General Linux timing method
public:
int CreateTimer();
int StartTimer(int index);
int StopTimer(int index);
public:
// retrieve time
double ReadTimer(int index);
// write into a file
double WriteTimer(int index);
public:
void Error(string str);
};
#endif
#endif // _PERF_TIMER_H_