PerfTest代码架构拆解138个测试用例如何被紧凑优雅地调度执行【免费下载链接】perftestGPU texture/buffer performance tester项目地址: https://gitcode.com/gh_mirrors/pe/perftest想深入理解 GPU 纹理与缓冲性能测试工具 PerfTest 的代码架构这篇拆解会带你看看一个仅 400 多行的主程序如何调度执行 138 个 GPU 微基准测试用例并且做到结构紧凑、逻辑清晰。PerfTest 是一个基于 DirectX 11 的开源 GPU 性能测试工具专门用来测量各种 Buffer、Texture 资源在 L1 缓存内的数据加载性能帮助渲染程序员选择正确的资源类型。它的代码量不大但架构设计相当讲究值得一读。138 个测试用例从哪来一张测试矩阵看懂全貌打开主程序perftest/main.cpp你会发现测试用例不是零散罗列的而是一张规整的矩阵。整个测试体系围绕三个维度展开维度可选值组合出的用例数资源类型Typed Buffer、ByteAddress Buffer、Structured Buffer、Constant Buffer、Texture2D5 大类访问模式uniform统一地址、linear线性合并、random随机偏移3 种数据宽度R8 / R16F / R32F / RG8 / RG16F / RG32F / RGBA8 / RGBA16F / RGBA32F 等多档例如BufferR8.Load uniform、ByteAddressBuffer.Load4 unaligned random、Texture2DRGBA32F.Sample(bilinear) linear……这些名字本身就是资源类型 访问模式 数据宽度的完整描述。三大维度相乘正好构成138 个测试用例——这也是整个项目最核心的资产。代码架构全景三层各司其职PerfTest 的代码组织非常清爽可以分成三个层次调度层 perftest/main.cpp —— 定义测试矩阵、逐帧派发 设备层 perftest/directx.h/cpp —— 封装 D3D11 设备、资源创建、性能查询 着色器层 perftest/*.hlsl —— 每个用例对应的计算着色器调度层main()函数加载全部着色器、创建缓冲与纹理资源然后在帧循环里逐个调用bench.testCase(...)派发任务设备层DirectXDevice类把所有 D3D11 样板代码创建设备、交换链、缓冲、纹理、SRV/UAV收拢在一起还给每个用例配上计时能力着色器层每类资源一个.hlsl用宏拼出不同变体。一页着色器如何撑起几十个用例模板宏的魔法这是全项目最精妙的设计测试用例的繁殖不靠复制代码而靠宏组合。以perftest/loadRawBody.hlsli为例这个公共主体文件里用三个宏控制行为LOAD_INVARIANT所有线程读同一地址uniformLOAD_LINEAR地址按线程号递增触发 GPU 合并访问coalescingLOAD_RANDOM地址加 0~15 随机偏移破坏合并、模拟真实随机访问。而LOAD_WIDTH控制单次加载的宽度1/2/3/4 个分量。于是形如perftest/loadRaw1dLinear.hlsl的外壳文件只需要写三行#define LOAD_WIDTH 1 #define LOAD_LINEAR #include loadRawBody.hlsli1 个主体文件 12 个外壳文件 12 个 raw 加载用例。类似的套路还有loadTypedBody.hlsli、loadStructuredBody.hlsli、loadTexBody.hlsli、sampleTexBody.hlsli。这正是整个项目紧凑优雅的根源——新增一个测试维度往往只需新增一个几行的外壳文件。计时黑科技用 GPU 时间戳查询精确定时要测 138 个用例的性能CPU 侧秒表显然不够格。PerfTest 用的是 DirectX 11 的 **GPU timestamp query时间戳查询**机制每个用例派发前startPerformanceQuery()记录起始时间戳派发完成后endPerformanceQuery()记录结束时间戳若干帧后processPerformanceResults()用GetData()取回结果换算成毫秒。代码在perftest/directx.h里预分配了 4096 个查询槽位std::arrayPerformanceQuery, 4096以环形方式复用足够容纳所有用例。main.cpp中的BenchTest类则像一个调度小助手testCase()把开始计时 → 派发 → 结束计时三步打包让每个用例的调度代码只有一行。防作弊设计如何让编译器老老实实干活做微基准测试最怕的是编译器把没用的代码优化掉。PerfTest 用了两个巧妙的防作弊手段详见perftest/loadConstantsGPU.h写掩码writeIndex每个着色器在循环里做 256 次加载最后写入一块 groupshared 内存再条件性地写回输出缓冲。这个条件由运行时常量控制且永远为假——但编译器不知道这一点于是不敢删掉任何一次加载地址掩码elementsMask加载地址会与一个运行时常量做|运算编译器无法在编译期证明地址是连续的也就没法把多个窄加载合并成宽加载。正是这些细节保证了 138 个用例测出来的数字真正反映硬件行为而不是编译器优化的产物。结果输出归一化对比一眼看懂差距测试跑完后main.cpp会以BufferRGBA8.Load random为基准1.0x把其余 137 个用例的时间归一化成倍数逐行打印BufferR8.Load uniform: 11.302ms 3.907x BufferR8.Load linear: 11.327ms 3.899x BufferR8.Load random: 44.150ms 1.000x倍数越大代表相对基准越快。比如 uniform 地址加载比 random 快近 4 倍这一眼就能看出统一地址访问对某些资源类型有多重要——这正是 README 中大量分析结论如 Nvidia 常量缓冲、Intel/AMD 统一加载优化的来源。小结给想上手读代码的你PerfTest 的代码架构可以概括为三句话调度集中所有用例在main.cpp的帧循环里有序排队一次跑完全部设备封装DirectXDevice屏蔽了 D3D11 的繁琐细节让主程序专注于测试逻辑着色器模板化用宏组合替代代码复制让 138 个用例的着色器源码总量保持在极小规模。如果你也想给自己的项目写微基准测试这套模板宏 时间戳查询 防优化技巧的组合拳非常值得借鉴。想深入研究的话推荐从这三个文件入手perftest/main.cpp调度与测试矩阵、perftest/directx.cpp性能查询实现、perftest/loadRawBody.hlsli着色器模板范式。【免费下载链接】perftestGPU texture/buffer performance tester项目地址: https://gitcode.com/gh_mirrors/pe/perftest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考