AMD Ryzen™ Performance Guide

性能 指南

Ryzen 7000 Nolid

AMD Ryzen CPU 性能指南

最初发布:
最后更新:

更快地设计。更快地渲染。更快地迭代。

我们的AMD Ryzen™性能指南将通过一系列技巧、窍门和诀窍,帮助您完成优化过程,支持您追求卓越性能。

工具

PresentMon

PresentMon是一个命令行界面(CLI)工具,用于记录帧时间,例如MsBetweenPresents

示例

终端窗口
PresentMon-1.6.0-x64.exe -process_name "MyGame.exe"
-stop_existing_session
-terminate_on_proc_exit
-terminate_after_timed
-timed 60
-output_file "%CD%\result\presentmon.csv"

Open Capture and Analysis Tool (OCAT)

OCAT是一个图形用户界面(GUI)工具,支持热键,用于记录基于PresentMon的帧时间。

Windows®性能工具包

Windows性能分析器 (WPA)

WPA是一个高度可配置的工具,用于查找系统性能瓶颈,并且非常适合过滤和可视化调用堆栈。 

GPUView

GPUView是一个用于分析GPU性能的工具,特别是关于直接内存访问(DMA)缓冲区处理。

Visual Studio 并发可视化工具

您可以使用Visual Studio的并发可视化工具来定位性能瓶颈、CPU利用率不足、线程争用、跨核心线程迁移、同步延迟、DirectX活动、重叠I/O区域以及其他信息。

AMD µProf

  • 使用CPU硬件性能监控计数器(PMCs)查找性能瓶颈
    • 基于指令的采样(IBS)具有与指令相关的准确归因,但计数器覆盖范围有限。
    • 基于事件的采样(EBS)具有更多可用计数器,但归因精度较低。通常在几个指令范围内是准确的。AMD Dev Techs经常在评估性能(扩展)配置文件中使用EBS计数器。
  • 请参阅 https://developer.amd.com/amd-uprof/

Radeon GPU Profiler (RGP)

RGP是一款适用于DirectX、Vulkan®、SPIR-V™、OpenGL®和OpenCL™的离线编译器和性能分析工具。

编译

使用最新的编译器和Windows SDK

添加病毒和威胁防护排除项

  • 将项目文件夹添加到病毒和威胁防护设置的排除项中,以加快构建时间。
    • 我们已经看到一些项目的编译速度提高了20%!

CPU性能分析首选发布配置构建

  • 调试和开发配置构建可能会大大降低性能。
    • 统计数据收集可能会导致缓存污染。
    • 日志记录可能会创建串行化点。
    • 有时调试构建可能会禁用多线程优化。
  • 在调查未解决的问题时,开发人员可能会提交启用测试和发布配置上调试功能的更改请求。在发布之前,请务必禁用调试功能!
  • 需要验证的某些Unreal Engine设置包括

禁用防篡改以进行CPU性能分析

  • 构建一个与发布配置类似但没有防篡改或反作弊工具的二进制文件,这些工具可能会阻止CPU性能分析工具正确加载符号。

测试

审核内容

向艺术家和QA寻求场景推荐

  • 使用代表性内容进行性能分析非常重要。并非所有场景都相同,而且不总是有最好的场景。
    • 室内场景可能具有重度遮挡。
    • 室外森林可能有许多蒙版材质。
    • 大量人群可能代表AI、导航网格、物理、动画和渲染工作负载的良好压力测试。
  • 保持一致的游戏内日间时间是最小化运行间差异的重要考虑因素。
    • 白天时间可能会触发特定的世界事件,例如有更多人群的繁忙时段,或者白天和夜晚之间有不同的光照组合。

使用默认平台时钟设置

警告

使用超出规格或工厂设置的AMD处理器可能导致的损坏不在您的AMD产品保修范围内,也可能不在您的系统制造商的保修范围内。在超出规格或工厂设置(包括但不限于超频)的情况下运行您的AMD处理器,可能会损坏或缩短您的处理器或其他系统组件的寿命,造成系统不稳定(例如数据丢失和图像损坏),在极端情况下可能导致系统完全失效。AMD不为超出处理器规格或工厂设置的情况相关的任何问题或损坏提供支持或服务。

测试首次用户体验的冷着色器缓存

  • 请确保清除应用程序的着色器缓存(如果它有的话)。
    • 最终用户通常不会像开发人员那样连续运行相同的场景。
  • 下面的示例清除Microsoft®、AMD和NVIDIA®的着色器缓存
终端窗口
rem Run as administrator
rem Disable Steam Shader Pre-Caching before running this script
rem Reboot after running this script to clear any shaders still in system memory
setlocal enableextensions
cd /d "%~dp0"
rmdir /s /q "%LOCALAPPDATA%\D3DSCache"
rmdir /s /q "%LOCALAPPDATA%\AMD\DxCache"
rmdir /s /q "%LOCALAPPDATA%\AMD\GLCache"
rmdir /s /q "%LOCALAPPDATA%\AMD\VkCache"
rmdir /s /q "%ProgramData%\NVIDIA Corporation\NV_Cache"
rmdir /s /q "%ProgramFiles(x86)%\Steam\steamapps\shadercache"

分析帧时间

  • 在进行性能分析时,首选平均值和百分位数,而不是最小值和最大值指标。
    • 一个糟糕的帧就足以使最小值和最大值不再代表平均体验。
  • 在比较3西格玛及以上时,请确保收集足够的样本。
  • 确定许多测试迭代中的变异系数。
    • 根据我们的经验,低于3%是好的。
  • 高变异性表明测试场景不一致。
    • 我们建议为动态生成的内容设置静态种子值,并固定白天时间等变量。
    • 如果不可避免地存在较高的变异性,用户应相应地增加其基准测试运行次数。

性能分析

在需要时禁用内存完整性

Hypervisor-Protected Code Integrity (HVCI)在Windows安全应用程序中标记为内存完整性

添加符号 

symstore和符号路径可以是加载供应商符号以及为不检查本地目录的工具提供提示的强大工具。

  • 编辑_NT_SYMBOL_PATH的系统环境变量。
    •  示例
终端窗口
_NT_SYMBOL_PATH=cache*c:\symbols;srv*https://download.amd.com/dir/bin;srv*https://driver-symbols.nvidia.com/;srv*http://msdl.microsoft.com/download/symbols
  • 安装包含symchk.exe和symstore.exe的Windows 10 SDK调试器。建议将“C:\Program Files (x86)\Windows Kits\10\Debuggers\x64”添加到PATH
  • 存储您项目的符号。
    •  示例
终端窗口
symstore.exe add /r /f *.pdb /s c:\symbols /t "MyProject"

确定是否受CPU限制

通常,如果GPU空闲时间> 5%,则应用程序受CPU限制。

  • 在RGP、GPUView和Visual Studio并发可视化工具等工具中查找GPU上的空闲工作气泡。

  • 有多种工具和方法可供开发人员检测边界性。

  • Radeon GPU Profiler (RGP)

Radeon GPU Profiler

  • GPUView
    • 警告:适配器硬件队列3D是衡量GPU忙碌程度的良好指标,但请务必缩放到一个修剪日志头部和尾部(可能缺少事件)的选定范围。
    • 警告:此捕获通常限于几秒钟,可能太宽泛,无法看到较小的空闲时段。考虑使用缩放功能将范围限制在每帧几秒钟。
    • 示例
终端窗口
rem run as administrator
rem add "C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\gpuview" to path
setlocal enableextensions
cd /d "%~dp0"
rem switch active foreground window back to the game application
timeout.exe /t 5
call log.cmd light
timeout.exe /t 5
call log.cmd
rem open Merged.etl
  • Windows性能记录器和Windows性能分析器
    • 警告:Windows性能分析器的GPU利用率(FM)(按进程计算)在百分比计算中排除了GPU空闲时间。幸运的是,您可以在GPUView中打开etl文件。
    • 注意:此捕获通常限于几秒钟。
    • 示例
终端窗口
rem run as administrator
setlocal enableextensions
cd /d "%~dp0"
rem switch active foreground window back to the game application
timeout.exe /t 5
wpr.exe -start gpu -filemode
timeout.exe /t 5
wpr.exe -stop out.etl
rem open out.etl
  • Visual Studio 并发可视化工具
    • 线程视图显示DirectX GPU引擎利用率,可用于缩放到GPU空闲的区域,以便进一步分析阻塞的线程。

验证UE4并行渲染

命令推荐值
r.rhicmdbypass0
r.rhicmdusedeferredcontexts1
r.rhicmduseparallelalgorithms1
r.rhithread.enable1

验证并行DX12管线状态创建

使用冷着色器缓存同时验证并行DX12管线状态创建。

  1. 安装Windows SDK Windows性能工具包。
  2. 将GPUView文件夹添加到PATH
终端窗口
rem run as administrator
rem clear shader cache
call log.cmd
rem collect samples while game is starting and calling D3D12.dll!CDevice::CreatePipelineState
call log.cmd
  • 使用Windows性能分析器打开合并的etl日志文件。
  • 添加CPU使用率(精确)CPU使用率(采样)按进程、堆栈的火焰图。
  • 按进程、堆栈的火焰图中查找所有D3D12.dll!CDevice::CreatePipelineState

此查找命令突出显示了CPU使用率(精确)图中的相关样本。

验证并行DX12命令列表生成

  • 安装Windows SDK Windows性能工具包。
  • 将GPUView文件夹添加到PATH
终端窗口
rem run as administrator
rem add "C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\gpuview" to path
setlocal enableextensions
cd /d "%~dp0"
rem switch active foreground window back to the game application
timeout.exe /t 5
call log.cmd
rem collect samples while game is playing and rendering frames. 1 seconds should be more than enough data.
timeout.exe /t 1
call log.cmd
  • 添加GPU利用率CPU使用率(精确)通用事件图。
  • 将视图缩放到两个Present标记之间的一个帧。
  • 通用事件图中,将CPU列移到任务名称旁边,然后筛选并展开命令列表

调试

WinDbg

WinDbg可用于设置断点、日志记录、跳过函数、编辑内存或编辑寄存器。

  • 对于任何函数,前四个参数分别在RCXRDXR8R9中。第五个及更高的参数通过堆栈传递。
  • 注意:Steam游戏通常需要steam_appid.txt文件或SteamAppId系统环境变量才能从WinDbg启动可执行文件。
  • 验证是否使用了DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE
    • 在混合图形系统上,为了获得最佳性能,建议使用DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE (2)
    • 这些WinDbg命令可能有助于
终端窗口
bp dxgi!CDXGIFactory::EnumAdapterByGpuPreference ".printf \"FOUND DXGIFactory::EnumAdapterByGpuPreference DXGI_GPU_PREFERENCE=%x\\n\",@r8"
  • 验证GetLogicalProcessorInformation(Ex)调用是否具有非零输入缓冲区长度并返回成功
    • 某些应用程序错误地假设了缓冲区大小,并且可能会崩溃,尤其是在具有许多逻辑处理器的系统上。
    • 测试第一次调用是否具有输入缓冲区长度0以获取要malloc的缓冲区长度。
    • 测试所有非零输入缓冲区长度的调用是否都成功返回(return 1)。
    • 这些WinDbg命令可能有助于
终端窗口
bp kernelbase!GetLogicalProcessorInformation "bp /1 @$ra \".printf \\\"GetLogicalProcessorInformation returned %i\\\", @rax; .echo; g\"; .printf \"GetLogicalProcessorInformation input buffer length 0x%x\", poi(@rdx); .echo; g"
bp kernelbase!GetLogicalProcessorInformationEx "bp /1 @$ra \".printf \\\"GetLogicalProcessorInformationEx returned %i\\\", @rax; .echo; g\"; .printf \"GetLogicalProcessorInformationEx input buffer length 0x%x\", poi(@r8); .echo; g"

集成显卡

测试集成显卡

DirectX API通过术语统一内存架构(UMA)来引用加速处理单元(APU)或集成显卡。

DirectX 12

bool isUMA(ID3D12Device* pDevice)
{
bool result = false;
D3D12_FEATURE_DATA_ARCHITECTURE data = {};
if (S_OK == pDevice->CheckFeatureSupport(
D3D12_FEATURE_ARCHITECTURE,
&data,
sizeof(data)))
{
result = data.UMA;
}
return result;
}
完整的示例代码在此:isUMA_d3d12.cpp
//
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
//
#include <iostream>
#include <dxgi1_4.h>
#include <d3d12.h>
#pragma comment( lib, "dxgi" )
#pragma comment( lib, "d3d12" )
bool isUMA(ID3D12Device* pDevice)
{
bool result = false;
D3D12_FEATURE_DATA_ARCHITECTURE data = {};
if (S_OK == pDevice->CheckFeatureSupport(
D3D12_FEATURE_ARCHITECTURE,
&data,
sizeof(data)))
{
result = data.UMA;
}
return result;
}
int main()
{
ID3D12Device* pDevice = nullptr;
if (SUCCEEDED(D3D12CreateDevice(
NULL,
D3D_FEATURE_LEVEL_11_0,
_uuidof(ID3D12Device),
(void**)&pDevice)))
{
IDXGIFactory* pFactory;
IDXGIFactory4* pFactory4;
if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&pFactory)))
&& SUCCEEDED(pFactory->QueryInterface(__uuidof(IDXGIFactory4), (void**)&pFactory4)))
{
LUID luid = pDevice->GetAdapterLuid();
IDXGIAdapter* pAdapter;
DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(pFactory4->EnumAdapterByLuid(luid, __uuidof(IDXGIAdapter), (void**)&pAdapter))
&& SUCCEEDED(pAdapter->GetDesc(&desc)))
{
printf("DedicatedVideoMemory %I64u\n", desc.DedicatedVideoMemory);
printf("DedicatedSystemMemory %I64u\n", desc.DedicatedSystemMemory);
printf("SharedSystemMemory %I64u\n", desc.SharedSystemMemory);
printf("isUMA %i\n", isUMA(pDevice));
SIZE_T budget = desc.DedicatedVideoMemory;
if (isUMA(pDevice))
{
budget += desc.DedicatedSystemMemory + desc.SharedSystemMemory;
}
IDXGIAdapter3* pAdapter3 = nullptr;
DXGI_QUERY_VIDEO_MEMORY_INFO info = {};
if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIAdapter3), (void**)&pAdapter3))
&& SUCCEEDED(pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info)))
{
budget = info.Budget;
}
printf("budget %I64u\n", budget);
}
}
}
}

DirectX 11.3

bool isUMA(ID3D11Device* pDevice)
{
bool result = false;
ID3D11Device3* pD3D11Device3 = nullptr;
if (S_OK == pDevice->QueryInterface(IID_PPV_ARGS(&pD3D11Device3)) && pD3D11Device3)
{
D3D11_FEATURE_DATA_D3D11_OPTIONS2 data = {};
if (S_OK == pD3D11Device3->CheckFeatureSupport(
D3D11_FEATURE_D3D11_OPTIONS2,
&data,
sizeof(data)))
{
result = data.UnifiedMemoryArchitecture;
}
pD3D11Device3->Release();
}
return result;
}
完整的示例代码在此:isUMA_d3d11_3.cpp
//
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
//
#include <iostream>
#include <dxgi1_4.h>
#include <d3d11_3.h>
#pragma comment( lib, "dxgi" )
#pragma comment( lib, "d3d11" )
bool isUMA(ID3D11Device* pDevice)
{
bool result = false;
ID3D11Device3* pD3D11Device3 = nullptr;
if (S_OK == pDevice->QueryInterface(IID_PPV_ARGS(&pD3D11Device3)) && pD3D11Device3)
{
D3D11_FEATURE_DATA_D3D11_OPTIONS2 data = {};
if (S_OK == pD3D11Device3->CheckFeatureSupport(
D3D11_FEATURE_D3D11_OPTIONS2,
&data,
sizeof(data)))
{
result = data.UnifiedMemoryArchitecture;
}
pD3D11Device3->Release();
}
return result;
}
int main()
{
UINT flags = NULL; // D3D11_CREATE_DEVICE_SINGLETHREADED;
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };
UINT numFeatureLevels = ARRAYSIZE(featureLevels);
D3D_FEATURE_LEVEL featureLevel;
ID3D11Device* pDevice = nullptr;
ID3D11DeviceContext* pImmediateContext = nullptr;
if SUCCEEDED(D3D11CreateDevice(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
flags,
featureLevels,
numFeatureLevels,
D3D11_SDK_VERSION,
&pDevice,
&featureLevel,
&pImmediateContext))
{
IDXGIDevice* pDXGIDevice = nullptr;
IDXGIAdapter* pAdapter = nullptr;
DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(pDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice))
&& SUCCEEDED(pDXGIDevice->GetAdapter(&pAdapter))
&& SUCCEEDED(pAdapter->GetDesc(&desc)))
{
printf("DedicatedVideoMemory %I64u\n", desc.DedicatedVideoMemory);
printf("DedicatedSystemMemory %I64u\n", desc.DedicatedSystemMemory);
printf("SharedSystemMemory %I64u\n", desc.SharedSystemMemory);
printf("isUMA %i\n", isUMA(pDevice));
SIZE_T budget = desc.DedicatedVideoMemory;
if (isUMA(pDevice))
{
budget += desc.DedicatedSystemMemory + desc.SharedSystemMemory;
}
IDXGIAdapter3* pAdapter3 = nullptr;
DXGI_QUERY_VIDEO_MEMORY_INFO info = {};
if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIAdapter3), (void**)&pAdapter3))
&& SUCCEEDED(pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info)))
{
budget = info.Budget;
}
printf("budget %I64u\n", budget);
}
}
}

为集成显卡正确计算VRAM预算

共享视频内存与CPU的集成显卡部分在检测VRAM预算时需要特殊考虑。

DirectX

首选方法

<code readonly="true" class="language-cpp">
<xmp>IDXGIAdapter3* pAdapter3 = nullptr;
DXGI_QUERY_VIDEO_MEMORY_INFO info = {};
if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIAdapter3), (void**)&pAdapter3))
&& SUCCEEDED(pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info)))
{
budget = info.Budget;
}</xmp>
</code>

备选方法

DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(pAdapter->GetDesc(&desc)))
{
SIZE_T budget = desc.DedicatedVideoMemory;
if (isUMA(pDevice))
{
budget += desc.DedicatedSystemMemory + desc.SharedSystemMemory;
}
}
完整的示例代码在此:isUMA_d3d12.cpp
//
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
//
#include <iostream>
#include <dxgi1_4.h>
#include <d3d12.h>
#pragma comment( lib, "dxgi" )
#pragma comment( lib, "d3d12" )
bool isUMA(ID3D12Device* pDevice)
{
bool result = false;
D3D12_FEATURE_DATA_ARCHITECTURE data = {};
if (S_OK == pDevice->CheckFeatureSupport(
D3D12_FEATURE_ARCHITECTURE,
&data,
sizeof(data)))
{
result = data.UMA;
}
return result;
}
int main()
{
ID3D12Device* pDevice = nullptr;
if (SUCCEEDED(D3D12CreateDevice(
NULL,
D3D_FEATURE_LEVEL_11_0,
_uuidof(ID3D12Device),
(void**)&pDevice)))
{
IDXGIFactory* pFactory;
IDXGIFactory4* pFactory4;
if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&pFactory)))
&& SUCCEEDED(pFactory->QueryInterface(__uuidof(IDXGIFactory4), (void**)&pFactory4)))
{
LUID luid = pDevice->GetAdapterLuid();
IDXGIAdapter* pAdapter;
DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(pFactory4->EnumAdapterByLuid(luid, __uuidof(IDXGIAdapter), (void**)&pAdapter))
&& SUCCEEDED(pAdapter->GetDesc(&desc)))
{
printf("DedicatedVideoMemory %I64u\n", desc.DedicatedVideoMemory);
printf("DedicatedSystemMemory %I64u\n", desc.DedicatedSystemMemory);
printf("SharedSystemMemory %I64u\n", desc.SharedSystemMemory);
printf("isUMA %i\n", isUMA(pDevice));
SIZE_T budget = desc.DedicatedVideoMemory;
if (isUMA(pDevice))
{
budget += desc.DedicatedSystemMemory + desc.SharedSystemMemory;
}
IDXGIAdapter3* pAdapter3 = nullptr;
DXGI_QUERY_VIDEO_MEMORY_INFO info = {};
if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIAdapter3), (void**)&pAdapter3))
&& SUCCEEDED(pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info)))
{
budget = info.Budget;
}
printf("budget %I64u\n", budget);
}
}
}
}
完整的示例代码在此:isUMA_d3d11_3.cpp
//
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
//
#include <iostream>
#include <dxgi1_4.h>
#include <d3d11_3.h>
#pragma comment( lib, "dxgi" )
#pragma comment( lib, "d3d11" )
bool isUMA(ID3D11Device* pDevice)
{
bool result = false;
ID3D11Device3* pD3D11Device3 = nullptr;
if (S_OK == pDevice->QueryInterface(IID_PPV_ARGS(&pD3D11Device3)) && pD3D11Device3)
{
D3D11_FEATURE_DATA_D3D11_OPTIONS2 data = {};
if (S_OK == pD3D11Device3->CheckFeatureSupport(
D3D11_FEATURE_D3D11_OPTIONS2,
&data,
sizeof(data)))
{
result = data.UnifiedMemoryArchitecture;
}
pD3D11Device3->Release();
}
return result;
}
int main()
{
UINT flags = NULL; // D3D11_CREATE_DEVICE_SINGLETHREADED;
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };
UINT numFeatureLevels = ARRAYSIZE(featureLevels);
D3D_FEATURE_LEVEL featureLevel;
ID3D11Device* pDevice = nullptr;
ID3D11DeviceContext* pImmediateContext = nullptr;
if SUCCEEDED(D3D11CreateDevice(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
flags,
featureLevels,
numFeatureLevels,
D3D11_SDK_VERSION,
&pDevice,
&featureLevel,
&pImmediateContext))
{
IDXGIDevice* pDXGIDevice = nullptr;
IDXGIAdapter* pAdapter = nullptr;
DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(pDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice))
&& SUCCEEDED(pDXGIDevice->GetAdapter(&pAdapter))
&& SUCCEEDED(pAdapter->GetDesc(&desc)))
{
printf("DedicatedVideoMemory %I64u\n", desc.DedicatedVideoMemory);
printf("DedicatedSystemMemory %I64u\n", desc.DedicatedSystemMemory);
printf("SharedSystemMemory %I64u\n", desc.SharedSystemMemory);
printf("isUMA %i\n", isUMA(pDevice));
SIZE_T budget = desc.DedicatedVideoMemory;
if (isUMA(pDevice))
{
budget += desc.DedicatedSystemMemory + desc.SharedSystemMemory;
}
IDXGIAdapter3* pAdapter3 = nullptr;
DXGI_QUERY_VIDEO_MEMORY_INFO info = {};
if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIAdapter3), (void**)&pAdapter3))
&& SUCCEEDED(pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info)))
{
budget = info.Budget;
}
printf("budget %I64u\n", budget);
}
}
}

优化集成显卡的扩展性

有时需要进行功能缩放,以便在热限制平台上实现可接受的帧率。

  • 尝试缩放的直接更改包括
    • 使用DXGI_FORMAT_R11G11B10_FLOAT而不是DXGI_FORMAT_R16G16B16A16_FLOAT
    • 降低阴影贴图质量。
    • 降低体积雾质量。
    • 禁用环境遮挡。
  • 以下相关的Unreal Engine CVar可能有所帮助
    • r.SceneColorFormat
    • r.AmbientOcclusionLevels

混合图形

为混合图形选择最佳GPU

为了确保混合图形平台上的预期GPU得到利用,可能需要额外的考虑。

  • Windows 10 v1803添加了IDXGIFactory6::EnumAdapterByGpuPreference
  • 对于游戏应用程序,请使用DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE
  • WinDbg可用于测试DXGI_GPU_PREFERENCE=2 (DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE)。
终端窗口
bp dxgi!CDXGIFactory::EnumAdapterByGpuPreference ".printf \"FOUND DXGIFactory::EnumAdapterByGpuPreference DXGI_GPU_PREFERENCE=%x\\n\",@r8"
  • 用户可以在图形设置中为每个应用程序更改首选项。
    • Dell G5 15 Special Edition (5505)的示例

Windows Set Graphics Preference

内存

优化memcpy/memset

  • 更新编译器以获得最新的memcpymemset和其他C运行时优化。
  • memcpy的源和目标对齐到4096字节页面边界,可以减少Zen 2的存储到加载转发事件(请参阅AMD µProf中的STLIOther)。
  • 将数据对齐到4096页面边界,可能有利于AMD Threadripper™和EPYC™处理器上的探针过滤。

避免假共享

  • 与本机缓存行大小(64字节)对齐可以减少假共享。
  • 使用对齐的内存分配器,如_aligned_mallocC++17 aligned new
  • 优先使用线程本地存储和局部变量,而不是进程共享数据。
    • 尝试使用每个线程的范围索引,以便线程范围避免共享相同的64字节缓存行或4096字节页面。
    • 尝试复制数据而不是使用进程共享数据。
  • 填充或重新排序结构在某些情况下可以减少假共享,特别是当多个线程使用同一缓存行的变量时。

优先使用匹配硬件预取器行为的数据访问模式

  • 流式传输
    • 利用内存访问模式的历史记录,以升序或降序获取其他顺序行。

Ryzen Streaming

  • 步幅
    • 利用单个指令的内存访问历史记录,当每次访问是常量时获取其他行。

Ryzen Stride

对经历缓存未命中的链接数据结构使用软件预取指令

  • 对经历缓存未命中的链接数据结构(如std::vector)使用软件预取指令。
    • 调整预取距离以考虑内存延迟。根据我们的经验,向前四个迭代是调整的良好起点。
  • 在一次性数据上使用NTA。
  • 在双线程模式下,请注意,一个线程过多的软件预取可能会从其共享缓存中逐出另一个线程的工作集。
  • 移除由PMCx052找到的无效软件预取。
  • AMD µProf评估性能(扩展)配置文件可能有助于查找来自DRAM的数据缓存填充。

同步

使用现代同步API

现代同步API包括std::mutexstd::shared_mutexSRWLockEnterCriticalSection

  • 它们可能比WaitForSingleObject或用户自旋锁更快,功耗更低。
  • 一些现代同步API有效地利用AMD的mwaitx指令来等待地址或超时。
  • 旧的同步API可能存在不必要的Syscall开销。
  • 用户自旋锁可能会不必要地消耗操作系统线程调度资源,因为操作系统调度程序可能无法确定是应该将控制权交给另一个程序线程,还是应该自旋。
    • 通常建议发出sleep/wait指令而不是自旋锁。
    • 即使在等待GPU时,像SetEventOnCompletion()这样的调用也可以与旧的fence轮询模型一样高效,同时避免使其他线程饿死或不必要地消耗电力。

测试应用程序从1到%NUMBER_OF_PROCESSORS%的可伸缩性

此建议特定于AMD处理器,并非对所有处理器供应商的通用指导。

通常,应用程序会显示SMT的好处,并建议使用所有逻辑处理器。然而,游戏在游戏过程中经常在主线程或渲染线程上遭受SMT争用。

  • 减少这种争用的一种策略是基于物理核心计数而不是逻辑处理器计数来创建线程。
  • 避免将线程池大小设置为常量。
  • 对应用程序/游戏进行性能分析以确定理想的线程数。
    • 游戏初始化,包括解压资产和编译/预热着色器,可能受益于使用SMT双线程模式的逻辑处理器。
    • 游戏玩法可能偏好使用SMT单线程模式的物理核心计数。
  • 我们建议创建开发人员选项以
    • 设置最大线程池大小。
    • 强制线程池大小。
    • 强制SMT。
    • 强制单NUMA节点(隐式分组)。
  • 针对多个CPU进行性能分析。这里没有一成不变的规则。
    • 最佳线程数启发式可能因低核心数和高核心数CPU而异。
    • 虽然12核CPU可能受益于您游戏中的空闲线程来处理操作系统和第三方应用程序的中断,但6核CPU可能需要每个计算资源都可用。
    • 开发人员可以调整低核心阈值以在不同核心数CPU上获得最佳性能。
  • AMD µProf可用于显示进程的实际线程并发直方图。
  • 查看
© . This site is unofficial and not affiliated with AMD.