Shader Cycles在GPU性能分析中的作用以及Shader Cycles的影响因素研究测试

一 、shader Cycles测试工具:

1.1 单个场景的所有shader获取

renderdoc截帧可以获取到设备反汇编出来的场景中的VS、FS shader。

如上图在Pipeline State窗口可以查看每一个DrawCall对应的Shader代码。同时点击Save可以保存当前DC对应的FS/VS shader到本地。

但由于一个场景几百个DC,不可能一个一个点击保存shader,需要批量进行导出。

renderdoc提供了python API接口,同时在renderdoc中提供了直接运行python脚本的窗口。

https://renderdoc.org/docs/python_api/qrenderdoc/main.html#qrenderdoc.CaptureContext.CurPipelineState

为了后面工具编译数据方便,将VS Shader保存为xxx.vert,将FS Shader保存为xxx.frag

1.2 shader编译

使用Mali提供的malioc工具来编译Shader

https://developer.arm.com/Tools%20and%20Software/Mali%20Offline%20Compiler

编译指令:

malioc.exe -f "xxx.frag" -d -c Mali-G57 #Mali-G57为期望Shader编译的对应平台

1.3 编译数据

malioc.exe -f D:\my_shader_exports\高级_家园_GOFCN\ResourceId__55_Program_Hidden_Internal-GUITexture.frag -d -c Mali-G57



Mali Offline Compiler v8.7.0 (Build cbd520)
Copyright (c) 2007-2025 Arm Limited. All rights reserved.

Configuration
=============

Hardware: Mali-G57 r0p1
Architecture: Valhall
Driver: r51p0-00rel0
Shader type: OpenGL ES Fragment

Main shader
===========

Work registers: 8 (25% used at 100% occupancy)
Uniform registers: 4 (3% used)
Stack use: false
16-bit arithmetic: 33%

                                A     FMA     CVT     SFU      LS       V       T    Bound
Total instruction cycles:    0.19    0.19    0.00    0.00    0.00    0.50    0.25        V
Shortest path cycles:        0.19    0.19    0.00    0.00    0.00    0.50    0.25        V
Longest path cycles:         0.19    0.19    0.00    0.00    0.00    0.50    0.25        V

A = Arithmetic, FMA = Arith FMA, CVT = Arith CVT, SFU = Arith SFU,
LS = Load/Store, V = Varying, T = Texture

Shader properties
=================

Has uniform computation: false
Has side-effects: false
Modifies coverage: false
Uses late ZS test: false
Uses late ZS update: false
Reads color buffer: false

Note: This tool shows only the shader-visible property state.
API configuration may also impact the value of some properties.

二、shader Cycles影响因素测试

2.1 同一个shader在不同架构的GPU上的表现研究

设备

三星Galaxy A03

红米12 C

GPU

Mali-G57 MP1

Mali-G52 MC2

GPU 架构

Valhall

Bifrost

Shader interPolator Cycles

2.06百万Cycles

2.72百万Cycles

Shader Arithmetic Cycles

3.16百万Cycles

5.79百万Cycles

Shader LoadStore Cycles

0.01百万cycles

0.04百万Cycles

Shader Texture Cycles

0.32百万Cycles

0.65百万Cycles

Work registers

31 (96% used at 100% occupancy)

31 (96% used at 100% occupancy)

Uniform registers

20 (15% used)

26 (20% used)

Total instruction cycles A

2.53

2.92

Total instruction cycles FMA

2.53

————

Total instruction cycles CVT

0.16

————

Total instruction cycles SFU

1.88

————

Total instruction cycles LS

0.00

0.00

Total instruction cycles V

1.50

1.50

Total instruction cycles T

0.00

0.00

上表中同一个shader在不同GPU上的主要差异:
Uniform registers使用数量不同:

这里简单了解下什么是Work Registers寄存器与Uniform Registers寄存器。

寄存器是GPU内部用来存放变量的存储单元,Work Registers为线程独享用来存放临时变量和中间结果的寄存器。Uniform为用来存放所有线程共享,shader外部传入的常量的寄存器。

Work Registers寄存器与计算复杂度有关但总体是GPU自行调度,想要优化的GPU Shader Cycles整体关系不大,暂时忽略。Uniform registers数量不同,同样为架构特性。

Mali-G52与Mali-G57算数单元同一个shader,算数单元Cycles差别比较大:

Mali-G52为Bifrost架构,Mali-G57为Valhall架构。下图官方文档中两种架构的架构图。可以发现在Valhall架构上,算数单元被细分同时可以并行执行。减少了算数指令在单一算数单元中排队等待的情况。

本测试得到的结论:

更复杂的数学运算对于Mali bifrost架构的设备对GPU占用的影响远比Valhall高的多,shader 不同硬件上做LOD是必要的,不同硬件做LOD时LOD值的指定应该考虑不同GPU架构的情况。

2.2 变量精度对shader Cycles的影响:highp、mediump(float、half)

测试用例:unity中找一个shader改成两份变量精度分别为Float,Half的shader。真机测试查看其Shader Cycles情况。

设备_精度

三星Galaxy A03_mediump

三星Galaxy A03_highp

红米12 C_mediump

红米12 C_highp

GPU

Mali-G57 MP1

Mali-G57 MP1

Mali-G52 MC2

Mali-G52 MC2

GPU 架构

Valhall

Valhall

Bifrost

Bifrost

Shader interPolator Cycles

1.2百万Cycles

2.06百万Cycles

1.53百万Cycles

2.72百万Cycles

Shader Arithmetic Cycles

2.9百万Cycles

3.16百万Cycles

5.19百万Cycles

5.79百万Cycles

Shader LoadStore Cycles

0.01百万Cycles

0.01百万cycles

0.04百万Cycles

0.04百万Cycles

Shader Texture Cycles

0.32百万Cycles

0.32百万Cycles

0.64百万Cycles

0.65百万Cycles

片段着色器数据:

Work registers

32 (100% used at 100% occupancy)

31 (96% used at 100% occupancy)

30 (93% used at 100% occupancy)

31 (96% used at 100% occupancy)

Uniform registers

14 (10% used)

20 (15% used)

20 (15% used)

26 (20% used)

16-bit arithmetic:

32%

0%

29%

0%

Total instruction cycles A

2.40

2.53

2.67

2.92

Total instruction cycles FMA

2.40

2.53

————

————

Total instruction cycles CVT

0.16

0.16

————

————

Total instruction cycles SFU

1.88

1.88

————

————

Total instruction cycles LS

0.00

0.00

0.00

0.00

Total instruction cycles V

1.00

1.50

1.00

1.50

Total instruction cycles T

0.00

0.00

0.00

0.00

顶点着色器数据:

--Position variant

Work registers

16 (50% used at 100% occupancy)

16 (50% used at 100% occupancy)

32 (100% used at 100% occupancy)

32 (100% used at 100% occupancy)

Uniform registers

40 (31% used)

40 (31% used)

48 (37% used)

48 (37% used)

16-bit arithmetic:

0%

0%

0%

0%

Total instruction cycles A

1.40

1.40

1.21

1.21

Total instruction cycles FMA

1.40

1.40

————

————

Total instruction cycles CVT

0.19

0.19

————

————

Total instruction cycles SFU

0.12

0.12

————

————

Total instruction cycles LS

3.00

3.00

1.00

1.00

Total instruction cycles T

0.00

0.00

0.00

0.00

--Varying variant

Work registers

13 (40% used at 100% occupancy)

20 (62% used at 100% occupancy)

23 (71% used at 100% occupancy)

24 (75% used at 100% occupancy)

Uniform registers

8 (6% used)

8 (6% used)

40 (31% used)

40 (31% used)

16-bit arithmetic:

N/A

N/A

N/A

N/A

Total instruction cycles A

0.28

0.28

0.08

0.08

Total instruction cycles FMA

0.00

0.00

————

————

Total instruction cycles CVT

0.28

0.28

————

————

Total instruction cycles SFU

0.00

0.00

————

————

Total instruction cycles LS

7.00

9.00

15.00

15.00

Total instruction cycles T

0.00

0.00

0.000

0.000

测试结论:

shader变量全局使用float对比half会导致:插值操作相关的shader Cycles大量增加,主要消耗发生在片元阶段对像素的插值操作。在对精度要求不是那么高在手机游戏上,尽可能的使用half精度的变量可以较大的减少Shader interPolator Cycles。

2.3 插值变量数量对Shader Cycles的影响

设备_精度

三星Galaxy A03_插值变量一个

三星Galaxy A03_插值变量5个

GPU

Mali-G57 MP1

Mali-G57 MP1

GPU 架构

Valhall

Valhall

Shader interPolator Cycles

0.8百万Cycles

2.06百万Cycles

Shader Arithmetic Cycles

0.3百万Cycles

0.63百万Cycles

Shader LoadStore Cycles

0.01百万Cycles

0.01百万Cycles

Shader Texture Cycles

0.43百万Cycles

0.32百万Cycles

片段着色器数据:

Work registers

6 (18% used at 100% occupancy)

17 (53% used at 100% occupancy)

Uniform registers

0 (0% used)

0 (0% used)

16-bit arithmetic:

N/A

0%

Total instruction cycles A

0.09

0.44

Total instruction cycles FMA

0.00

0.44

Total instruction cycles CVT

0.09

0.03

Total instruction cycles SFU

0.00

0.12

Total instruction cycles LS

0.00

0.00

Total instruction cycles V

0.25

1.25

Total instruction cycles T

0.00

0.00

测试结论:

插值变量数量主要对Shader interPolator Cycles的影响较大

2.4 计算复杂度对shader Cycles的影响

测试方法:每个shader只使用单独的计算函数且尽量只用一行计算。

FileNameShader Arithmetic CyclesTotal instruction cycles
_A
Total instruction cycles
_FMA
Total instruction cycles
_CVT
Total instruction cycles
_SFU
Total instruction cycles
_LS
Total instruction cycles
_V
Total instruction cycles
_T
cos)0.33百万Cycles0.250.250.120.2500.120
sin()0.33百万Cycles0.250.250.120.2500.120
sqrt()0.25百万Cycles0.2500.090.2500.250
exp()0.25百万Cycles0.160.030.160.1200.250
LerpClamp()0.25百万Cycles0.160.090.16000.250
log()0.21百万Cycles0.160.120.160.1200.250
log2()0.21百万Cycles0.160.090.160.1200.250
exp2()0.21百万Cycles0.120.030.120.1200.250
加减乘除0.22百万Cycles0.120.120.060.1200.250
max()0.22百万Cycles0.1200.12000.250
rsqrt()0.18百万Cycles0.120.030.090.1200.250
dot()0.14百万Cycles0.090.060.09000.250
Pow()0.14百万Cycles0.090.060.09000.120
FileNameShader Arithmetic CyclesTotal instruction cycles
_A
Total instruction cycles
_LS
Total instruction cycles
_V
Total instruction cycles
_T
cos()1.030.4600.120
sin()1.030.4600.120
log()0.880.3800.250
log2()0.80.3800.250
exp2()0.880.3300.250
sqrt()0.80.3300.250
dot()0.650.2900.250
exp()0.880.2900.250
加减乘除0.880.2900.250
Pow()0.650.2900.120
rsqrt()0.730.2900.250
LerpClamp()0.730.2500.250
max()0.580.2500.250

测试结论:

更复杂的数学函数计算直接影响Shader Arithmetic Cycles,三角函数计算是所有数学计算中复杂程度最高的。

valhall架构由于可以并行计算对比bifrost架构优化比较明显。

2.5 贴图对shaderCycles的影响

Mali-G57:

测试用例Shader Texture CyclesTotal instruction cycles_ATotal instruction cycles_FMATotal instruction cycles_CVTTotal instruction cycles_SFUTotal instruction cycles_LSTotal instruction cycles_VTotal instruction cycles_T
1张512*512贴图 采样1次0.6000000.250.25
1张512*512贴图 采样2次0.90.190.190000.250.5
1张512*512贴图 采样3次1.180.310.310000.250.75
采样1张贴图 每张1次0.6000000.250.25
采样2张贴图 每张1次0.90.120.120000.250.5
采样3张贴图 每张1次1.180.190.190000.250.75
1张256*256贴图 采样3次1.180.310.310000.250.75
1张512*512贴图 采样3次1.180.310.310000.250.75
1张1024*1024贴图 采样3次1.180.310.310000.250.75

Mali-G52

FileNameTotal instruction cycles_ATotal instruction cycles_LSTotal instruction cycles_VTotal instruction cycles_T
1张512*512贴图 采样1次0.0800.250.5
1张512*512贴图 采样2次0.2100.251
1张512*512贴图 采样3次0.3800.251.5
采样1张贴图 每张1次0.3800.251.5
采样2张贴图 每张1次0.3800.251.5
采样3张贴图 每张1次0.3800.251.5
1张256*256贴图 采样3次0.0800.250.5
1张512*512贴图 采样3次0.1700.251
1张1024*1024贴图 采样3次0.2100.251.5

测试结论:

Shader Texture Cycles主要受实际shader中采样次数的影响,采三张贴图在shader中每张采样一次和采样一张贴图在shader中每张采样三次总的Shader Texture Cycles相同。同时Shader Texture Cycles不受实际贴图的分辨率影响。

2.6 Overdraw对场景Shader Cycles的影响

测试方法:

1.不采样贴图的半透面片叠加

2.采样贴图的半透面片叠加

测试用例总shader CyclesShader InterPolator Cyclesshader Arithmetic CyclesShader LoadStore Cyclesshader Texture Cycles
不采样贴图,叠加1个半透面片2.381.250.790.020.32
不采样贴图,叠加100个半透面片4.61.312.870.060.36
采样1张雾效贴图,叠加1个半透面片2.641.360.820.020.44
采样1张雾效贴图,叠加一百个半透面片16.697.42.420.426.44

测试结论:

Overdraw会线性放大Shader的所有消耗,对于采样了贴图的半透明特效贴图采样和插值消耗增加尤其明显。

2.7 向量归一化计算:dot+inversesqrt 与直接使用normalize计算之间的区别

官方文档中有这样一段话:避免编写自己的运算。

dot+inversesqrt是做归一化向量计算的

normalize也是做归一化向量计算的

猜想:直接使用normalize指令更少性能更好

验证发现:

在移动端真机上normalize会被转化成dot+inversesqrt再做计算 性能没有差异

同样的pow会被转换成log2+exp2的形式计算

2.8 总结

Shader Interpolator Cycles
  • 含义:主要统计由顶点着色器到片段着色器插的插值操作

  • 影响因素:插值变量的数量、插值变量的精度(float/half)

Shader Arithmetic Cycles
  • 含义:统计所有算术运算的消耗,包括加减乘除、三角函数、对数等等

  • 影响因素:单个shader中计算量的多少及数学运算函数的复杂度

Shader Texture Cycles
  • 含义:统计纹理采样的消耗

  • 影响因素:纹理采样次数

三、shader Cycles到底是怎么统计出来的以及shader各种指标的探究

3.1 shaderCyclesde的计算方法

从上面简单的测试,得到了shaderCycles的的一部分影响因素。

官方的测试工具Streamline中并不直接统计GPU Shader Cycles,只有UWA这样统计,官方统计的是统计的core unit Utilization。

不过从core unit Utilization的计算方式可以反推出GPU Shader Cycles的计算方式:


Arithmetic unit utilization: max(min(($MaliALUInstructionsExecutedInstructions / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

Varying unit utilization: max(min((($MaliVaryingUnitIssues32BitInterpolationIssues + $MaliVaryingUnitIssues16BitInterpolationIssues) / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

Texture unit utilization: max(min(($MaliTextureUnitCyclesTextureFilteringActive / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

Load/store unit utilization: max(min((($MaliLoadStoreUnitCyclesFullRead + $MaliLoadStoreUnitCyclesPartialRead + $MaliLoadStoreUnitCyclesFullWrite + $MaliLoadStoreUnitCyclesPartialWrite + $MaliLoadStoreUnitCyclesAtomicAccess) / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

上方所有除号前面的值就是每个unit的Cycles。

从上面的计算方法可以得到,计算单元、插值单元、贴图采样单元、LS单元工作的总Cycles加来等于MaliShaderCoreCyclesExecutionCoreActive的Cycles,也就是所有着色器核心活跃的周期数。那么一个GPU的着色器核心总Cycles上限应该是多少?

https://developer.arm.com/documentation/102642/0107/Shader-core-data-path?lang=en

在官网中找到了这样一段关于着色器核心利用率计算的描述:


着色器核心利用率=(着色器核心活跃周期数/着色器核心个数/GPU活跃周期数)*100%

那么其实就可以得到某个GPU着色器核心活跃周期数的上限:


MaliShaderCoreCyclesExecutionCoreActive的最大值=着色器核心个数*GPU理论上最大的活跃周期数

以Mali-G57 MP1为例:

GPU Clocks:GPU 频率:

384MHz~650MHz之间切换

GPU 时钟周期数: 384,000,000 cycles~650,000,000 cycles

时钟周期为时钟频率取倒数即GPU 时钟周期耗时为 1/384,000,000~1/650,000,000=2.604ns~1.538ns

GPU名称中的MP1为此GPU的最大核心数量。

也就是说Valhall架构的最大核心数为1的Mali-G57 MP1,其理论上着色器核心活跃周期数的上限等于GPU活跃时钟周期数的上限,也就是每秒650,000,000Cycles。

用一个Mali-G76 MP10的设备,使用unity构建一个使用了无比复杂的shader的场景的demo真机测试采集数据:

Mali-G76 MP10的shader核心数量为10个,理论上复杂场景的GPU Total cycles应该远大于GPU 时钟周期数,见下图数据,GPU ToTal Cycles的总数为GPU 活跃时钟周期数的9.22倍,符合理论。

从这里再次回看3.1的对比测试,在之前的理解里,Mali-G52 MC2设备上,总的shader Cycles更高,GPU性能消耗更大,GPU耗时会更高。但现在看来似乎并非如此。找到之前的某一份测试数据对数据做补充整理数据如下表:

设备

三星Galaxy A03

红米12 C

GPU

Mali-G57 MP1

Mali-G52 MC2

GPU 架构

Valhall

Bifrost

Shader Core Count

1

2

Total Sahder Cycles

1.27百万Cycles/帧

2.36百万Cycles/帧

GPU Clocks

133.24万Clocks/帧

87.06万cycles/帧

GPU Time

6.20ms

5.70ms

Fragment shaded

236.85万个/帧

244.05万个/帧

GPU shader instructions

0.32 百万个/帧

1.02百万个/帧

GPU Cycles/Pixel

0.57 Cycles/帧

0.36 cycles/帧

可以发现,虽然Mali-G52 MC2上的shader Cycles更高,但整体GPU耗时其实更低。不能说明shader在Mali-G52 MC2运行表现的性能更差。

3.2 Mali官方各指标的计算方法解析

3.2.1 GPU 性能的汇总指标:Mali GPU Usage、Mali GPU Utilization GPU

对应GPU top level图。

GPU active cycles:

GPU 活跃周期,只要GPU中任意队列工作,此指标都会递增。

Non-Fragment QueQue active:

非片元队列活跃周期。

Fragment QueQue active:

片元队列活跃周期

3.2.2 shader Core的汇总指标:Mali Core Utilization、Mali shader Core Cycles

指标统计重点关注一下Utilization的计算方法:

Non-fragment utilization:

max(min(($MaliShaderCoreCyclesNonFragmentActive / $MaliConstantsShaderCoreCount / $MaliGPUCyclesGPUActive) * 100, 100), 0)

Fragment utilization:

max(min(($MaliShaderCoreCyclesFragmentActive / $MaliConstantsShaderCoreCount / $MaliGPUCyclesGPUActive) * 100, 100), 0)

Fragment FPK buffer utilization:

max(min(($MaliShaderCoreCyclesFragmentFPKBufferActive / $MaliShaderCoreCyclesFragmentActive) * 100, 100), 0)

Execution core utilization:

max(min(($MaliShaderCoreCyclesExecutionCoreActive / $MaliConstantsShaderCoreCount / $MaliGPUCyclesGPUActive) * 100, 100), 0)

可以发现计算都是各指标除以shader core数量再除以Mali GPU cycles

3.2.3 shader core unit相关指标
3.2.3.1 Mali ALU Instructions
Valhall架构

$MaliALUInstructionsBlendShaderCalls: 混合着色器调用次数

$MaliALUInstructionsCVTPipeInstructions:类型转换管线执行指令数

$MaliALUInstructionsDivergedInstructions:分支指令执行数

$MaliALUInstructionsFMAPipeInstructions:乘加融合计算指令执行执行数

$MaliALUInstructionsSFUPipeInstructions:特殊函数计算指令执行数

那么对于此架构的GPU 总的着色器指令数就是


Mali ALU Instructions = MaliALUInstructionsCVTPipeInstructions + MaliALUInstructionsFMAPipeInstructions + MaliALUInstructionsSFUPipeInstructions

Bifrost架构

对于Bifrost架构,计算单元中没有再被细分,因此这里统计:$MaliALUInstructionsExecutedInstructions 就是总的shader指令数

3.2.3.2 Mali Core Unit Utilization
Valhall架构

Arithmetic unit utilization:

计算单元在可编程核心中的利用百分比。计算公式如下:

max(min((max($MaliALUInstructionsFMAPipeInstructions, max($MaliALUInstructionsCVTPipeInstructions, $MaliALUInstructionsSFUPipeInstructions * 4)) / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

从这个公式可以发现,由于Valhall架构计算单元中FMA、CVT、SFU并行,最终的占用百分比是取三个计算管线中最大的一个来除以shader Core的活跃周期。

在优化计算单元时应该结合各个计算管线的指令先优化指令数最高的管线。

Varying unit utilization:

变量单元的利用率。计算公式如下:

max(min((($MaliVaryingUnitIssues32BitInterpolationIssues + $MaliVaryingUnitIssues16BitInterpolationIssues) / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

从公式看优化的方式主要就是减少变量的数量。

Texture unit utilization:

纹理单元的利用率。

max(min(($MaliTextureUnitCyclesTextureFilteringActive / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

对于纹理单元,官方的计算方法是纹理过滤操作活跃的周期数。每次采样纹理都会触发一次过滤操作,同时不同的采样方式差别较大,优化方式主要是应该减少采样次数同时使用性能更好的过滤方式。

Bifrost架构

Arithmetic unit utilization:

max(min(($MaliALUInstructionsExecutedInstructions / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

Varying unit utilization:

max(min((($MaliVaryingUnitIssues32BitInterpolationIssues + $MaliVaryingUnitIssues16BitInterpolationIssues) / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

Texture unit utilization:

max(min(($MaliTextureUnitCyclesTextureFilteringActive / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

Load/store unit utilization:

max(min((($MaliLoadStoreUnitCyclesFullRead + $MaliLoadStoreUnitCyclesPartialRead + $MaliLoadStoreUnitCyclesFullWrite + $MaliLoadStoreUnitCyclesPartialWrite + $MaliLoadStoreUnitCyclesAtomicAccess) / $MaliShaderCoreCyclesExecutionCoreActive) * 100, 100), 0)

四、shader Cycles在GPU分析中的的作用

同样的需要从GPU架构的角度去思考:

先判断问题出在FS还是VS阶段:

再判断Execution core以外的消耗

这里一般主要关注Fragment warps数量是不是增加

UWA 中的FS Shaded应该就是这里的 Fragment warps * 此GPU架构每个Warps的thread数量

最后判断Execution core中到底是哪个单元消耗较大

如果 Fragment warps没有变大 则再去分析Execution core是不是增加的的比较多,里面最高的unit是什么。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值