mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-02 14:28:05 +02:00
nak: Add spill/fill statistics
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33773>
This commit is contained in:
parent
0480d8294c
commit
2a0302967f
8 changed files with 111 additions and 28 deletions
|
|
@ -146,6 +146,18 @@ struct nak_shader_info {
|
|||
/** Number of cycles used by fixed-latency instructions */
|
||||
uint32_t num_static_cycles;
|
||||
|
||||
/** Number of spills from GPRs to Memory */
|
||||
uint32_t num_spills_to_mem;
|
||||
|
||||
/** Number of fills from Memory to GPRs */
|
||||
uint32_t num_fills_from_mem;
|
||||
|
||||
/** Number of spills between register files */
|
||||
uint32_t num_spills_to_reg;
|
||||
|
||||
/** Number of fills between register files */
|
||||
uint32_t num_fills_from_reg;
|
||||
|
||||
/** Size of shader local (scratch) memory */
|
||||
uint32_t slm_size;
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,10 @@ impl ShaderBin {
|
|||
max_warps_per_sm: info.max_warps_per_sm,
|
||||
num_instrs: info.num_instrs,
|
||||
num_static_cycles: info.num_static_cycles,
|
||||
num_spills_to_mem: info.num_spills_to_mem,
|
||||
num_fills_from_mem: info.num_fills_from_mem,
|
||||
num_spills_to_reg: info.num_spills_to_reg,
|
||||
num_fills_from_reg: info.num_fills_from_reg,
|
||||
slm_size: info.slm_size,
|
||||
crs_size: sm.crs_size(info.max_crs_depth),
|
||||
__bindgen_anon_1: match &info.stage {
|
||||
|
|
@ -317,6 +321,10 @@ impl ShaderBin {
|
|||
eprintln!("Instruction count: {}", c_info.num_instrs);
|
||||
eprintln!("Static cycle count: {}", c_info.num_static_cycles);
|
||||
eprintln!("Max warps/SM: {}", c_info.max_warps_per_sm);
|
||||
eprintln!("Spills to mem: {}", c_info.num_spills_to_mem);
|
||||
eprintln!("Spills to reg: {}", c_info.num_spills_to_reg);
|
||||
eprintln!("Fills from mem: {}", c_info.num_fills_from_mem);
|
||||
eprintln!("Fills from reg: {}", c_info.num_fills_from_reg);
|
||||
eprintln!("Num GPRs: {}", c_info.num_gprs);
|
||||
eprintln!("SLM size: {}", c_info.slm_size);
|
||||
|
||||
|
|
|
|||
|
|
@ -1419,7 +1419,7 @@ impl Shader<'_> {
|
|||
for file in spill_files {
|
||||
let num_regs = self.sm.num_regs(file);
|
||||
if max_live[file] > num_regs {
|
||||
f.spill_values(file, num_regs);
|
||||
f.spill_values(file, num_regs, &mut self.info);
|
||||
|
||||
// Re-calculate liveness after we spill
|
||||
live = SimpleLiveness::for_function(f);
|
||||
|
|
@ -1461,7 +1461,7 @@ impl Shader<'_> {
|
|||
total_gprs = max_gprs;
|
||||
gpr_limit = total_gprs - u32::from(tmp_gprs);
|
||||
|
||||
f.spill_values(RegFile::GPR, gpr_limit);
|
||||
f.spill_values(RegFile::GPR, gpr_limit, &mut self.info);
|
||||
|
||||
// Re-calculate liveness one last time
|
||||
live = SimpleLiveness::for_function(f);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ fn init_info_from_nir(nak: &nak_compiler, nir: &nir_shader) -> ShaderInfo {
|
|||
num_gprs: 0,
|
||||
num_instrs: 0,
|
||||
num_static_cycles: 0,
|
||||
num_spills_to_mem: 0,
|
||||
num_fills_from_mem: 0,
|
||||
num_spills_to_reg: 0,
|
||||
num_fills_from_reg: 0,
|
||||
num_control_barriers: 0,
|
||||
slm_size: nir.scratch_size,
|
||||
max_crs_depth: 0,
|
||||
|
|
|
|||
|
|
@ -203,6 +203,10 @@ impl<'a> TestShaderBuilder<'a> {
|
|||
num_control_barriers: 0,
|
||||
num_instrs: 0,
|
||||
num_static_cycles: 0,
|
||||
num_spills_to_mem: 0,
|
||||
num_fills_from_mem: 0,
|
||||
num_spills_to_reg: 0,
|
||||
num_fills_from_reg: 0,
|
||||
slm_size: 0,
|
||||
max_crs_depth: 0,
|
||||
uses_global_mem: true,
|
||||
|
|
|
|||
|
|
@ -7458,6 +7458,10 @@ pub struct ShaderInfo {
|
|||
pub num_control_barriers: u8,
|
||||
pub num_instrs: u32,
|
||||
pub num_static_cycles: u32,
|
||||
pub num_spills_to_mem: u32,
|
||||
pub num_fills_from_mem: u32,
|
||||
pub num_spills_to_reg: u32,
|
||||
pub num_fills_from_reg: u32,
|
||||
pub slm_size: u32,
|
||||
pub max_crs_depth: u32,
|
||||
pub uses_global_mem: bool,
|
||||
|
|
|
|||
|
|
@ -85,21 +85,24 @@ trait Spill {
|
|||
fn fill(&mut self, dst: Dst, src: SSAValue) -> Box<Instr>;
|
||||
}
|
||||
|
||||
struct SpillUniform {}
|
||||
struct SpillUniform<'a> {
|
||||
info: &'a mut ShaderInfo,
|
||||
}
|
||||
|
||||
impl SpillUniform {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
impl<'a> SpillUniform<'a> {
|
||||
fn new(info: &'a mut ShaderInfo) -> Self {
|
||||
Self { info }
|
||||
}
|
||||
}
|
||||
|
||||
impl Spill for SpillUniform {
|
||||
impl Spill for SpillUniform<'_> {
|
||||
fn spill_file(&self, file: RegFile) -> RegFile {
|
||||
debug_assert!(file.is_uniform());
|
||||
file.to_warp()
|
||||
}
|
||||
|
||||
fn spill(&mut self, dst: SSAValue, src: Src) -> Box<Instr> {
|
||||
self.info.num_spills_to_reg += 1;
|
||||
Instr::new_boxed(OpCopy {
|
||||
dst: dst.into(),
|
||||
src: src,
|
||||
|
|
@ -107,6 +110,7 @@ impl Spill for SpillUniform {
|
|||
}
|
||||
|
||||
fn fill(&mut self, dst: Dst, src: SSAValue) -> Box<Instr> {
|
||||
self.info.num_fills_from_reg += 1;
|
||||
Instr::new_boxed(OpR2UR {
|
||||
dst: dst,
|
||||
src: src.into(),
|
||||
|
|
@ -114,15 +118,17 @@ impl Spill for SpillUniform {
|
|||
}
|
||||
}
|
||||
|
||||
struct SpillPred {}
|
||||
struct SpillPred<'a> {
|
||||
info: &'a mut ShaderInfo,
|
||||
}
|
||||
|
||||
impl SpillPred {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
impl<'a> SpillPred<'a> {
|
||||
fn new(info: &'a mut ShaderInfo) -> Self {
|
||||
Self { info }
|
||||
}
|
||||
}
|
||||
|
||||
impl Spill for SpillPred {
|
||||
impl Spill for SpillPred<'_> {
|
||||
fn spill_file(&self, file: RegFile) -> RegFile {
|
||||
match file {
|
||||
RegFile::Pred => RegFile::GPR,
|
||||
|
|
@ -133,6 +139,7 @@ impl Spill for SpillPred {
|
|||
|
||||
fn spill(&mut self, dst: SSAValue, src: Src) -> Box<Instr> {
|
||||
assert!(matches!(dst.file(), RegFile::GPR | RegFile::UGPR));
|
||||
self.info.num_spills_to_reg += 1;
|
||||
if let Some(b) = src.as_bool() {
|
||||
let u32_src = if b {
|
||||
Src::new_imm_u32(!0)
|
||||
|
|
@ -154,6 +161,7 @@ impl Spill for SpillPred {
|
|||
|
||||
fn fill(&mut self, dst: Dst, src: SSAValue) -> Box<Instr> {
|
||||
assert!(matches!(src.file(), RegFile::GPR | RegFile::UGPR));
|
||||
self.info.num_fills_from_reg += 1;
|
||||
Instr::new_boxed(OpISetP {
|
||||
dst: dst,
|
||||
set_op: PredSetOp::And,
|
||||
|
|
@ -167,15 +175,17 @@ impl Spill for SpillPred {
|
|||
}
|
||||
}
|
||||
|
||||
struct SpillBar {}
|
||||
struct SpillBar<'a> {
|
||||
info: &'a mut ShaderInfo,
|
||||
}
|
||||
|
||||
impl SpillBar {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
impl<'a> SpillBar<'a> {
|
||||
fn new(info: &'a mut ShaderInfo) -> Self {
|
||||
Self { info }
|
||||
}
|
||||
}
|
||||
|
||||
impl Spill for SpillBar {
|
||||
impl Spill for SpillBar<'_> {
|
||||
fn spill_file(&self, file: RegFile) -> RegFile {
|
||||
assert!(file == RegFile::Bar);
|
||||
RegFile::GPR
|
||||
|
|
@ -183,6 +193,7 @@ impl Spill for SpillBar {
|
|||
|
||||
fn spill(&mut self, dst: SSAValue, src: Src) -> Box<Instr> {
|
||||
assert!(dst.file() == RegFile::GPR);
|
||||
self.info.num_spills_to_reg += 1;
|
||||
Instr::new_boxed(OpBMov {
|
||||
dst: dst.into(),
|
||||
src: src,
|
||||
|
|
@ -192,6 +203,7 @@ impl Spill for SpillBar {
|
|||
|
||||
fn fill(&mut self, dst: Dst, src: SSAValue) -> Box<Instr> {
|
||||
assert!(src.file() == RegFile::GPR);
|
||||
self.info.num_fills_from_reg += 1;
|
||||
Instr::new_boxed(OpBMov {
|
||||
dst: dst,
|
||||
src: src.into(),
|
||||
|
|
@ -200,15 +212,17 @@ impl Spill for SpillBar {
|
|||
}
|
||||
}
|
||||
|
||||
struct SpillGPR {}
|
||||
struct SpillGPR<'a> {
|
||||
info: &'a mut ShaderInfo,
|
||||
}
|
||||
|
||||
impl SpillGPR {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
impl<'a> SpillGPR<'a> {
|
||||
fn new(info: &'a mut ShaderInfo) -> Self {
|
||||
Self { info }
|
||||
}
|
||||
}
|
||||
|
||||
impl Spill for SpillGPR {
|
||||
impl Spill for SpillGPR<'_> {
|
||||
fn spill_file(&self, file: RegFile) -> RegFile {
|
||||
assert!(file == RegFile::GPR);
|
||||
RegFile::Mem
|
||||
|
|
@ -216,6 +230,7 @@ impl Spill for SpillGPR {
|
|||
|
||||
fn spill(&mut self, dst: SSAValue, src: Src) -> Box<Instr> {
|
||||
assert!(dst.file() == RegFile::Mem);
|
||||
self.info.num_spills_to_mem += 1;
|
||||
Instr::new_boxed(OpCopy {
|
||||
dst: dst.into(),
|
||||
src: src,
|
||||
|
|
@ -224,6 +239,7 @@ impl Spill for SpillGPR {
|
|||
|
||||
fn fill(&mut self, dst: Dst, src: SSAValue) -> Box<Instr> {
|
||||
assert!(src.file() == RegFile::Mem);
|
||||
self.info.num_fills_from_mem += 1;
|
||||
Instr::new_boxed(OpCopy {
|
||||
dst: dst,
|
||||
src: src.into(),
|
||||
|
|
@ -1023,26 +1039,31 @@ impl Function {
|
|||
/// just for the sake of a parallel copy. While this may not be true in
|
||||
/// general, especially not when spilling to memory, the register allocator
|
||||
/// is good at eliding unnecessary copies.
|
||||
pub fn spill_values(&mut self, file: RegFile, limit: u32) {
|
||||
pub fn spill_values(
|
||||
&mut self,
|
||||
file: RegFile,
|
||||
limit: u32,
|
||||
info: &mut ShaderInfo,
|
||||
) {
|
||||
match file {
|
||||
RegFile::GPR => {
|
||||
let spill = SpillGPR::new();
|
||||
let spill = SpillGPR::new(info);
|
||||
spill_values(self, file, limit, spill);
|
||||
}
|
||||
RegFile::UGPR => {
|
||||
let spill = SpillUniform::new();
|
||||
let spill = SpillUniform::new(info);
|
||||
spill_values(self, file, limit, spill);
|
||||
}
|
||||
RegFile::Pred => {
|
||||
let spill = SpillPred::new();
|
||||
let spill = SpillPred::new(info);
|
||||
spill_values(self, file, limit, spill);
|
||||
}
|
||||
RegFile::UPred => {
|
||||
let spill = SpillPred::new();
|
||||
let spill = SpillPred::new(info);
|
||||
spill_values(self, file, limit, spill);
|
||||
}
|
||||
RegFile::Bar => {
|
||||
let spill = SpillBar::new();
|
||||
let spill = SpillBar::new(info);
|
||||
spill_values(self, file, limit, spill);
|
||||
}
|
||||
_ => panic!("Don't know how to spill {} registers", file),
|
||||
|
|
|
|||
|
|
@ -1263,6 +1263,36 @@ nvk_shader_get_executable_statistics(
|
|||
stat->value.u64 = shader->info.max_warps_per_sm;
|
||||
}
|
||||
|
||||
vk_outarray_append_typed(VkPipelineExecutableStatisticKHR, &out, stat) {
|
||||
WRITE_STR(stat->name, "Spills to memory");
|
||||
WRITE_STR(stat->description, "Number of spills from GPRs to memory");
|
||||
stat->format = VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR;
|
||||
stat->value.u64 = shader->info.num_spills_to_mem;
|
||||
}
|
||||
|
||||
vk_outarray_append_typed(VkPipelineExecutableStatisticKHR, &out, stat) {
|
||||
WRITE_STR(stat->name, "Fills from memory");
|
||||
WRITE_STR(stat->description, "Number of fills from memory to GPRs");
|
||||
stat->format = VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR;
|
||||
stat->value.u64 = shader->info.num_spills_to_mem;
|
||||
}
|
||||
|
||||
vk_outarray_append_typed(VkPipelineExecutableStatisticKHR, &out, stat) {
|
||||
WRITE_STR(stat->name, "Spills to reg");
|
||||
WRITE_STR(stat->description,
|
||||
"Number of spills between different register files");
|
||||
stat->format = VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR;
|
||||
stat->value.u64 = shader->info.num_spills_to_reg;
|
||||
}
|
||||
|
||||
vk_outarray_append_typed(VkPipelineExecutableStatisticKHR, &out, stat) {
|
||||
WRITE_STR(stat->name, "Fills from reg");
|
||||
WRITE_STR(stat->description,
|
||||
"Number of fills between different register files");
|
||||
stat->format = VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR;
|
||||
stat->value.u64 = shader->info.num_fills_from_reg;
|
||||
}
|
||||
|
||||
vk_outarray_append_typed(VkPipelineExecutableStatisticKHR, &out, stat) {
|
||||
WRITE_STR(stat->name, "Code Size");
|
||||
WRITE_STR(stat->description,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue