Files
TheRock/rocm-systems/projects/rocprofiler-sdk/source/lib/aqlprofile/pm4/spm_builder.h
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

556 lines
26 KiB
C++

// MIT License
//
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in 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:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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
// AUTHORS 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 IN
// THE SOFTWARE.
#ifndef SRC_PM4_SPM_BUILDER_H_
#define SRC_PM4_SPM_BUILDER_H_
#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
#include "lib/aqlprofile/pm4/cmd_config.h"
#include "lib/aqlprofile/pm4/cmd_builder.h"
#include "lib/aqlprofile/core/spm_common.hpp"
namespace pm4_builder
{
class CmdBuffer;
class CmdBuilder;
// SpmBuilder config
typedef TraceConfig SpmConfig;
// Encapsulates the various Api and structures that are used to enable
// a SPM session and collect its data. Implementations of this
// interface program device specific registers to realize the functionality
class SpmBuilder
{
public:
// Destructor of the SPM service handle
virtual ~SpmBuilder() {}
// Builds Pm4 command stream to program hardware registers that
// enable a SPM session, including the issue of an event
// to begin thread session
virtual void Begin(CmdBuffer* cmd_buffer,
const SpmConfig* config,
const counters_vector& counters_vec) = 0;
// Builds Pm4 command stream to program hardware registers that
// disable a SPM session, including the issue of an event
// to stop currently ongoing thread session
virtual void End(CmdBuffer* cmd_buffer, const SpmConfig* config) = 0;
};
template <typename Builder, typename Primitives>
class GpuSpmBuilder
: public SpmBuilder
, protected Primitives
{
typedef typename Primitives::mux_info_t mux_info_t;
void DebugTrace(uint32_t value)
{
CmdBuffer cmd_buffer;
uint32_t header[2] = {0, value};
APPEND_COMMAND_WRAPPER((&cmd_buffer), header);
}
Builder builder;
public:
explicit GpuSpmBuilder(const AgentInfo* agent_info)
: SpmBuilder()
, builder(acquire_ip_offset_table(agent_info))
{}
void Begin(CmdBuffer* cmd_buffer, const SpmConfig* config, const counters_vector& counters_vec)
{
// SPM parameters
const uint32_t sampling_rate = config->sampleRate;
const uint64_t buffer_ptr = reinterpret_cast<uint64_t>(config->data_buffer_ptr);
const uint32_t buffer_size = config->data_buffer_size;
// Initialize SPM counter buffer metadata.
// counter_map takes the index of counters_vector as input, and output an index to
// the 16bit SPM counter buffer
SpmBufferDesc* spm_buffer_desc = (SpmBufferDesc*) config->data_buffer_ptr;
spm_buffer_desc->version = 1;
uint16_t* counter_map = spm_buffer_desc->get_counter_map();
memset(counter_map, 0, SPM_DESC_SIZE - sizeof(SpmBufferDesc));
// On Vega this is needed to collect Perf Cntrs: enable clock for performance counters
if(Primitives::GFXIP_LEVEL == 9)
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_PERFMON_CLK_CNTL_ADDR, 1);
// Program Grbm to broadcast messages to all shader engines
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::GRBM_GFX_INDEX_ADDR, Primitives::grbm_broadcast_value());
// Issue a CSPartialFlush cmd including cache flush
builder.BuildWriteWaitIdlePacket(cmd_buffer);
// SPM counters stop
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::CP_PERFMON_CNTL_ADDR,
Primitives::cp_perfmon_cntl_spm_stop_value());
// SPM counters reset
//
// We cannot call 'SPM counters reset' in user mode because it will reset WPTR of the
// SPM ring buffer, RPTR must be adjusted as well but it can only be adjusted in KFD.
// Also we don't need to reset SPM counter the same way as we do for legacy PMC,
// because SPM counter will reset upon each new sample.
//
// The first reset after aqlprofile acquires SPM from KFD will be done in KFD.
// Also each time when user mode buffer is no longer made available to KFD, KFD will
// reset SPM counters.
//
// builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::CP_PERFMON_CNTL_ADDR,
// Primitives::cp_perfmon_cntl_reset_value());
// Issue a CSPartialFlush cmd including cache flush
builder.BuildWriteWaitIdlePacket(cmd_buffer);
// Hardcode PERFMON_RING_MODE to 3 (Stall and send interrupt) to match KFD
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::RLC_SPM_PERFMON_CNTL__ADDR,
Primitives::rlc_spm_perfmon_cntl_value(sampling_rate));
// Iterate through the list of blocks to create PM4 packets to read counter values
// Below pair.first is the block id of a counter event and pair.second is the index into
// counters_vec of the counter event
std::vector<std::vector<std::pair<int, int> > > counter_info_even(
Primitives::NUMBER_OF_BLOCKS);
std::vector<std::vector<std::pair<int, int> > > counter_info_odd(
Primitives::NUMBER_OF_BLOCKS);
// distribute counter events to counter_info_even and counter_info_odd according to their
// block id
for(uint32_t index = 0; index < counters_vec.size(); ++index)
{
auto& counter_des = counters_vec[index];
const auto& block_des = counter_des.block_des;
if(block_des.id == Primitives::SQ_BLOCK_ID && config->spm_sq_32bit_mode)
{
counter_info_even[block_des.id].push_back({block_des.id, index});
counter_info_odd[block_des.id].push_back({block_des.id, index});
}
else
{
if(counter_des.index % 2 == 0)
counter_info_even[block_des.id].push_back({block_des.id, index});
else
counter_info_odd[block_des.id].push_back({block_des.id, index});
}
}
// Sort counter_info_even and counter_info_odd by instance
auto compare = [&counters_vec](std::pair<int, int> a, std::pair<int, int> b) {
auto index_a = a.second;
auto index_b = b.second;
auto& counter_des_a = counters_vec[index_a];
auto& counter_des_b = counters_vec[index_b];
return (counter_des_a.block_des.index < counter_des_b.block_des.index) ||
((counter_des_a.block_des.index == counter_des_b.block_des.index) &&
(counter_des_a.index < counter_des_b.index));
};
for(size_t i = 0; i < Primitives::NUMBER_OF_BLOCKS; ++i)
{
if(!counter_info_even[i].empty())
{
sort(counter_info_even[i].begin(), counter_info_even[i].end(), compare);
}
if(!counter_info_odd[i].empty())
{
sort(counter_info_odd[i].begin(), counter_info_odd[i].end(), compare);
}
}
// compute segment size for global(0) and se(1)
uint32_t ss_even[2] = {};
uint32_t ss_odd[2] = {};
for(size_t i = 0; i < Primitives::NUMBER_OF_BLOCKS; ++i)
{
if(!counter_info_even[i].empty())
{
const auto& counter_des = counters_vec[counter_info_even[i][0].second];
const auto* block_info = counter_des.block_info;
if(block_info->attr & CounterBlockSpmGlobalAttr)
{
ss_even[0] += counter_info_even[i].size();
}
else
{
ss_even[1] += counter_info_even[i].size();
}
}
if(!counter_info_odd[i].empty())
{
const auto& counter_des = counters_vec[counter_info_odd[i][0].second];
const auto* block_info = counter_des.block_info;
if(block_info->attr & CounterBlockSpmGlobalAttr)
ss_odd[0] += counter_info_odd[i].size();
else
ss_odd[1] += counter_info_odd[i].size();
}
}
// if SPM global is streamed we also stream time stamp.
ss_even[0] += Primitives::RLC_SPM_TIMESTAMP_SIZE16;
uint32_t ss[2] = {};
for(int i = 0; i < 2; ++i)
{
ss_even[i] = ss_even[i] / Primitives::RLC_SPM_COUNTERS_PER_LINE +
uint32_t(ss_even[i] % Primitives::RLC_SPM_COUNTERS_PER_LINE > 0);
ss_odd[i] = ss_odd[i] / Primitives::RLC_SPM_COUNTERS_PER_LINE +
uint32_t(ss_odd[i] % Primitives::RLC_SPM_COUNTERS_PER_LINE > 0);
ss[i] = std::max(ss_even[i], ss_odd[i]) * 2;
}
// fill in mux_ram data according to even and odd arrays
std::vector<mux_info_t> mux_ram[2];
mux_info_t mxinf = {0xFFFF};
// global mux_ram: initialize with all 0xFFFF.
mux_ram[0].resize(ss[0] * Primitives::RLC_SPM_COUNTERS_PER_LINE + 2);
std::fill(mux_ram[0].begin(), mux_ram[0].end(), mxinf);
// se mux_ram: initialize with all 0xFFFF (end of muxsel).
mux_ram[1].resize(ss[1] * Primitives::RLC_SPM_COUNTERS_PER_LINE + 2);
std::fill(mux_ram[1].begin(), mux_ram[1].end(), mxinf);
size_t even_idx = 0;
size_t odd_idx = Primitives::RLC_SPM_COUNTERS_PER_LINE;
// follow the exact steps to fill in mux_ram as when the number of even/odd events are
// counted Register timestamp
mxinf.data = Primitives::spm_timestamp_muxsel();
for(even_idx = 0; even_idx < Primitives::RLC_SPM_TIMESTAMP_SIZE16; ++even_idx)
{
mux_ram[0][even_idx] = mxinf;
}
// fill in global mux_sram after global time stamp
for(size_t j = 0; j < Primitives::NUMBER_OF_BLOCKS; ++j)
{
if(!counter_info_even[j].empty())
{
const auto& counter_des = counters_vec[counter_info_even[j][0].second];
const auto* block_info = counter_des.block_info;
if(block_info->attr & CounterBlockSpmGlobalAttr)
{
for(size_t k = 0; k < counter_info_even[j].size(); ++k)
{
const auto index = counter_info_even[j][k].second;
const auto& counter_des = counters_vec[index];
mux_ram[0][even_idx] = Primitives::spm_mux_ram_value(counter_des);
counter_map[index] = even_idx | 0x8000;
even_idx = Primitives::spm_mux_ram_idx_incr(even_idx);
}
for(size_t k = 0; k < counter_info_odd[j].size(); ++k)
{
const auto index = counter_info_odd[j][k].second;
const auto& counter_des = counters_vec[index];
mux_ram[0][odd_idx] = Primitives::spm_mux_ram_value(counter_des);
counter_map[index] = odd_idx | 0x8000;
odd_idx = Primitives::spm_mux_ram_idx_incr(odd_idx);
}
}
}
}
// fill in SE mux_ram
even_idx = 0;
odd_idx = Primitives::RLC_SPM_COUNTERS_PER_LINE;
for(size_t j = 0; j < Primitives::NUMBER_OF_BLOCKS; ++j)
{
// Use this code to do 32-bit SQ profiling
if(j == Primitives::SQ_BLOCK_ID && config->spm_sq_32bit_mode)
{
for(size_t k = 0; k < counter_info_even[j].size(); ++k)
{
const auto index = counter_info_even[j][k].second;
const auto& counter_des = counters_vec[index];
const auto counter = uint16_t(counter_des.index) * 2;
const auto block = Primitives::SQ_BLOCK_SPM_ID;
const auto instance = uint16_t(counter_des.block_des.index);
mux_ram[1][even_idx] = Primitives::spm_mux_ram_value(counter, block, instance);
counter_map[index] = even_idx;
even_idx = Primitives::spm_mux_ram_idx_incr(even_idx);
}
for(size_t k = 0; k < counter_info_odd[j].size(); ++k)
{
const auto index = counter_info_odd[j][k].second;
const auto& counter_des = counters_vec[index];
const auto counter = uint16_t(counter_des.index) * 2 + 1;
const auto block = Primitives::SQ_BLOCK_SPM_ID;
const auto instance = uint16_t(counter_des.block_des.index);
mux_ram[1][odd_idx] = Primitives::spm_mux_ram_value(counter, block, instance);
// fix corrupted upper 16-bit by setting its mux_sel to be 0x0
mux_ram[1][odd_idx] = mux_info_t{0x0};
odd_idx = Primitives::spm_mux_ram_idx_incr(odd_idx);
}
}
else
{
if(!counter_info_even[j].empty())
{
const auto& counter_des = counters_vec[counter_info_even[j][0].second];
const auto* block_info = counter_des.block_info;
if(!(block_info->attr & CounterBlockSpmGlobalAttr))
{
for(size_t k = 0; k < counter_info_even[j].size(); ++k)
{
const auto index = counter_info_even[j][k].second;
const auto& counter_des = counters_vec[index];
mux_ram[1][even_idx] = Primitives::spm_mux_ram_value(counter_des);
counter_map[index] = even_idx;
even_idx = Primitives::spm_mux_ram_idx_incr(even_idx);
}
for(size_t k = 0; k < counter_info_odd[j].size(); ++k)
{
const auto index = counter_info_odd[j][k].second;
const auto& counter_des = counters_vec[index];
mux_ram[1][odd_idx] = Primitives::spm_mux_ram_value(counter_des);
counter_map[index] = odd_idx;
odd_idx = Primitives::spm_mux_ram_idx_incr(odd_idx);
}
}
}
}
}
if(config->spm_sample_delay_max)
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::GRBM_GFX_INDEX_ADDR, Primitives::grbm_broadcast_value());
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::RLC_SPM_PERFMON_SAMPLE_DELAY_MAX__ADDR,
config->spm_sample_delay_max);
}
for(const auto& counter_des : counters_vec)
{
const auto* block_info = counter_des.block_info;
const auto& reg_info = block_info->counter_reg_info[counter_des.index];
bool is_spm_inited = false;
if(is_spm_inited == false)
{
is_spm_inited = true;
if(block_info->attr & CounterBlockSpmGlobalAttr)
{
// for each instance of a global block we program its delay
for(size_t j = 0; j < block_info->instance_count; ++j)
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
Primitives::GRBM_GFX_INDEX_ADDR,
Primitives::grbm_inst_se_sh_index_value(j, 0, 0));
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
block_info->delay_info.reg,
Primitives::get_spm_global_delay(counter_des, j));
}
}
else
{
for(size_t i = 0; i < config->se_number; ++i)
{
for(size_t j = 0; j < block_info->instance_count; ++j)
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
Primitives::GRBM_GFX_INDEX_ADDR,
Primitives::grbm_inst_se_index_value(j, i));
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
block_info->delay_info.reg,
Primitives::get_spm_se_delay(counter_des, i, j));
}
}
}
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::GRBM_GFX_INDEX_ADDR,
Primitives::grbm_broadcast_value());
}
// 4. Program the Block instance streaming performance counters in order to specify
// which items
// (events) the counters should count, if any. This is done by programming the
// GRBM_GFX_INDEX register to specify the type of access (broadcast or instance
// specific) followed by the actual register value. The first step may be to clear
// all counters of all instances to select zero (no counting). Then program the
// GRBM_GFX_INDEX, followed by the [BLK]_STRMPERFMON_SELECTx register.
// Setup counters
// Configure SQ block
if(block_info->attr & CounterBlockSqAttr)
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer, reg_info.select_addr, Primitives::sq_spm_select_value(counter_des));
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::SQ_PERFCOUNTER_MASK_ADDR,
Primitives::sq_mask_value(counter_des));
builder.BuildWriteUConfigRegPacket(
cmd_buffer, reg_info.control_addr, Primitives::sq_control_value(counter_des));
}
}
for(size_t i = 0; i < Primitives::NUMBER_OF_BLOCKS; ++i)
{
if(i == Primitives::SQ_BLOCK_ID) continue;
int instance = 0;
int je, jo,
j; // je & jo store even/odd array index, j stores index of counter registers
for(je = jo = j = 0; je < counter_info_even[i].size(); ++je, ++j)
{
// get 16-bit SPM select value for even counters
const auto& counter_des = counters_vec[counter_info_even[i][je].second];
uint32_t spm_select_value = Primitives::spm_even_select_value(counter_des);
if(counter_des.block_des.index != instance)
{
instance = counter_des.block_des.index;
// Reset counter register index when instance switches
j = 0;
}
// get 16-bit SPM select value for odd counters
if(jo < counter_info_odd[i].size())
{
const auto& counter_des = counters_vec[counter_info_odd[i][jo].second];
if(counter_des.block_des.index == instance)
{
spm_select_value |= Primitives::spm_odd_select_value(counter_des);
jo++;
}
}
const auto* block_info = counter_des.block_info;
int index = j >> 1;
int select = j % 2;
Register spm_select_addr = (select == 0)
? block_info->counter_reg_info[index].select_addr
: block_info->counter_reg_info[index].select1_addr;
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
Primitives::GRBM_GFX_INDEX_ADDR,
Primitives::grbm_inst_index_value(counter_des.block_des.index));
builder.BuildWriteConfigRegPacket(cmd_buffer, spm_select_addr, spm_select_value);
}
}
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::GRBM_GFX_INDEX_ADDR, Primitives::grbm_broadcast_value());
// Set segment size
uint32_t global_count = ss[0];
uint32_t se_count = ss[1];
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
Primitives::RLC_SPM_PERFMON_SEGMENT_SIZE__ADDR,
Primitives::rlc_spm_perfmon_segment_size_value(global_count, se_count));
if(config->spm_has_core1)
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer,
Primitives::RLC_SPM_PERFMON_SEGMENT_SIZE_CORE1__ADDR,
Primitives::rlc_spm_perfmon_segment_size_core1_value(se_count));
}
spm_buffer_desc->global_num_line = global_count;
spm_buffer_desc->se_num_line = se_count;
spm_buffer_desc->num_se = config->se_number;
spm_buffer_desc->num_sa = config->sa_number;
spm_buffer_desc->num_xcc = config->xcc_number;
spm_buffer_desc->num_events = counters_vec.size();
// Finish MUXSEL RAM
// 5. Program the RLC_[GLOBAL/SE]_MUXSEL_ADDR register with the starting address, likely
// zero.
if(!mux_ram[0].empty())
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_SPM_GLOBAL_MUXSEL_ADDR__ADDR, 0);
builder.BuildWriteRegDataPacket(cmd_buffer,
Primitives::RLC_SPM_GLOBAL_MUXSEL_DATA__ADDR,
reinterpret_cast<uint32_t*>(mux_ram[0].data()),
mux_ram[0].size() / 2,
1);
}
if(!mux_ram[1].empty())
{
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_SPM_SE_MUXSEL_ADDR__ADDR, 0);
builder.BuildWriteRegDataPacket(cmd_buffer,
Primitives::RLC_SPM_SE_MUXSEL_DATA__ADDR,
reinterpret_cast<uint32_t*>(mux_ram[1].data()),
mux_ram[1].size() / 2,
1);
}
// pm4SPM code has the following code
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_SPM_GLOBAL_MUXSEL_ADDR__ADDR, 0);
builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::RLC_SPM_SE_MUXSEL_ADDR__ADDR, 0);
// Issue a CSPartialFlush cmd including cache flush
builder.BuildWriteWaitIdlePacket(cmd_buffer);
// Program Compute Perfcount Enable register to support perf counting
builder.BuildWriteShRegPacket(cmd_buffer,
Primitives::COMPUTE_PERFCOUNT_ENABLE_ADDR,
Primitives::cp_perfcount_enable_value());
// SPM counters start
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::CP_PERFMON_CNTL_ADDR,
Primitives::cp_perfmon_cntl_spm_start_value());
// Issue a CSPartialFlush cmd including cache flush
builder.BuildWriteWaitIdlePacket(cmd_buffer);
}
void End(CmdBuffer* cmd_buffer, const SpmConfig* config)
{
// Program Grbm to broadcast messages to all shader engines
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::GRBM_GFX_INDEX_ADDR, Primitives::grbm_broadcast_value());
// Issue a CSPartialFlush cmd including cache flush
builder.BuildWriteWaitIdlePacket(cmd_buffer);
// SPM counters stop
builder.BuildWriteUConfigRegPacket(cmd_buffer,
Primitives::CP_PERFMON_CNTL_ADDR,
Primitives::cp_perfmon_cntl_spm_stop_value());
// SPM counters reset
// 'SPM counters reset' must be done in KFD. See comments in Begin() for more details
//
// builder.BuildWriteUConfigRegPacket(cmd_buffer, Primitives::CP_PERFMON_CNTL_ADDR,
// Primitives::cp_perfmon_cntl_reset_value());
// On Vega this disable clock for performance counters
if(Primitives::GFXIP_LEVEL == 9)
builder.BuildWriteUConfigRegPacket(
cmd_buffer, Primitives::RLC_PERFMON_CLK_CNTL_ADDR, 0);
}
};
} // namespace pm4_builder
#endif // SRC_PM4_SPM_BUILDER_H_