使用 DirectML 调试层
DirectML 调试层是可选的开发时组件,可帮助调试 DirectML 代码。 启用后,DirectML 调试层将包装 DirectML API 调用,并向开发人员提供其他验证和消息。 在单独的资料库 DirectML.Debug.dll
中实现调试层,该库在运行时由核心运行时库 DirectML.dll
有条件地加载。
强烈建议使用 DirectML 开发应用程序时启用调试层,因为它可以在 API 用法无效的情况下提供宝贵信息。
调试层消息概述
下面的代码示例说明了调试层如何帮助诊断不正确的 API 用法。 此代码尝试构造 DirectML 标识运算;因此输入和输出张量应具有相同的形状和数据类型。 但在本例中,我们展示的是输出张量参数中的错误。
uint32_t sizes[] = { 1 };
DML_BUFFER_TENSOR_DESC inputBufferDesc = {};
inputBufferDesc.DataType = DML_TENSOR_DATA_TYPE_FLOAT32;
inputBufferDesc.DimensionCount = ARRAYSIZE(sizes);
inputBufferDesc.Sizes = sizes;
inputBufferDesc.TotalTensorSizeInBytes = 256;
DML_BUFFER_TENSOR_DESC outputBufferDesc = {};
outputBufferDesc.DataType = DML_TENSOR_DATA_TYPE_FLOAT16; // Invalid: doesn't match input type!
outputBufferDesc.DimensionCount = ARRAYSIZE(sizes);
outputBufferDesc.Sizes = sizes;
outputBufferDesc.TotalTensorSizeInBytes = 256;
DML_TENSOR_DESC inputDesc = { DML_TENSOR_TYPE_BUFFER, &inputBufferDesc };
DML_TENSOR_DESC outputDesc = { DML_TENSOR_TYPE_BUFFER, &outputBufferDesc };
DML_ELEMENT_WISE_IDENTITY_OPERATOR_DESC identityDesc = {};
identityDesc.InputTensor = &inputDesc;
identityDesc.OutputTensor = &outputDesc;
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_ELEMENT_WISE_IDENTITY, &identityDesc };
Microsoft::WRL::ComPtr<IDMLOperator> op;
THROW_IF_FAILED(dmlDevice->CreateOperator(&opDesc, IID_PPV_ARGS(&op)));
如果没有 DirectML 调试层,创建运算符的最后一行将失败并返回 E_INVALIDARG
(0x80070057)。 THROW_IF_FAILED
宏(有关更多详细信息,请参阅 WIL)会将错误代码转换为通用消息“参数不正确”,并将其打印到调试器输出窗口。
TensorValidator.h(203)\DirectML.dll!00007FF83D25ADC9: (caller: 00007FF83D267523) Exception(1) tid(3b54) 80070057 The parameter is incorrect.
但是,启用 DirectML 调试层后,你将看到可用于缩小原因范围的其他信息:
D3D12 ERROR: Mismatched tensor data types. Tensor 'Output' has DataType of DML_TENSOR_DATA_TYPE_FLOAT16, while tensor 'Input' has DataType of DML_TENSOR_DATA_TYPE_FLOAT32. Both tensors are expected to have the same DataType. [ UNKNOWN ERROR #1: STRING_FROM_APPLICATION]
TensorValidator.h(203)\DirectML.Debug.dll!00007FF86DF66ADA: (caller: 00007FF86DF81646) Exception(1) tid(9f34) 80070057 The parameter is incorrect.
请注意扩展信息如何以 D3D12 ERROR 开头。 当 DirectML 调试层检测到问题时,它始终倾向于将错误消息发送到与 DirectML 设备创建期间传入的 ID3D12Device 关联的 ID3D12InfoQueue。 信息队列中的错误消息始终以 D3D12 ERROR 为前缀,如上所示;而且还可以使用 Direct3D 12 调试层消息回调以编程方式访问(请参阅博客文章 D3D12 调试层消息回调)。
仅当通过 ID3D12Debug::EnableDebugLayer 启用 Direct3D 12 调试层时,才能使用 ID3D12InfoQueue。 虽然最好同时启用(或禁用)Direct3D 12 和 DirectML 调试层,但较新版本的 DirectML 支持在未启用 Direct3D 12 调试层的情况下进行基本参数验证。 如果在尚未启用 Direct3D 12 调试层的情况下使用 DML_CREATE_DEVICE_FLAG_DEBUG 创建 DirectML 设备,则会使用 OutputDebugStringA 打印错误消息:
[DIRECTML WARNING]: enable the D3D debug layer for enhanced validation with DML_CREATE_DEVICE_FLAG_DEBUG.
[DIRECTML ERROR]: Mismatched tensor data types. Tensor 'Output' has DataType of DML_TENSOR_DATA_TYPE_FLOAT16, while tensor 'Input' has DataType of DML_TENSOR_DATA_TYPE_FLOAT32. Both tensors are expected to have the same DataType.
TensorValidator.h(218)\DirectML.Debug.dll!00007FF820C43AFB: (caller: 00007FF820C01CD1) Exception(1) tid(5df8) 80070057 The parameter is incorrect.
正如警告消息所示,最好在使用 DirectML 调试层时启用 Direct3D 12 调试层。 仅当同时启用这两个调试层时,才能进行某些类型的验证。
安装 DirectML 和 Direct3D 12 调试层(系统组件)
当使用 DirectML 作为系统组件时(请参阅 DirectML 版本历史记录),调试层是单独的图形工具包的一部分,作为按需功能 (FOD) 分发(请参阅按需功能)。 必须将图形工具 FOD 添加到系统中,才能将调试层与 DirectML 的系统版本配合使用。 FOD 还包含 Direct3D 12 调试层,该层对于调试 DirectML 应用程序也很有用(但不是必需的)。
要添加可选图形工具按需功能 (FOD) 包,请从管理员 Powershell 提示符运行以下命令。
Add-WindowsCapability -Online -Name "Tools.Graphics.DirectX~~~~0.0.1.0"
也可以在 Windows 设置中添加图形工具包。 在 Windows 10 22H2 和 Windows 11 上,导航到“设置”>“系统”>“可选功能”>“添加可选功能”,然后搜索“图形工具”。 在低于 Windows 10 22H2 的版本上,导航到“设置”>“应用”>“应用和功能”>“可选功能”>“添加可选功能”。
安装 DirectML 调试层(独立的可再分发组件)
将 DirectML 用作独立的可再分发组件库时(请参阅 Microsoft.AI.DirectML),DirectML 调试层与核心运行时库一起在包中提供。 将 DirectML.Debug.dll
和 DirectML.dll
放在应用程序的可执行文件旁边。
如果使用 Visual Studio 将 Microsoft.AI.DirectML
添加为 NuGet 包依赖项,该项目将在项目配置页中显示选项,以复制或跳过复制核心运行时和调试层库。 默认情况下,DirectML NuGet 包配置为始终将这两个 DLL 复制到项目输出文件夹。 但是,如果不使用调试层,可能需要跳过在发行版本中复制调试层的操作。
启用 Direct3D 12 调试层
Direct3D 12 的调试层 (d3d12sdklayers.dll
) 独立于 DirectML 调试层 (DirectML.Debug.dll
):DirectML 调试层为 DirectML API 使用情况提供增强的验证,Direct3D 12 调试层涵盖 Direct3D 12 API 使用情况。 但在实践中,最好在开发 DirectML 应用程序时同时启用这两个调试层。 Direct3D 12 调试层作为图形工具 FOD 的一部分安装,上面对此进行了说明。 有关如何激活 Direct3D 12 调试层的示例,请参阅 ID3D12Debug::EnableDebugLayer。
重要
必须先启用 Direct3D 12 调试层。 然后,通过调用 DMLCreateDevice 来启用 DirectML 调试层。
启用 DirectML 调试层
可以在调用 DMLCreateDevice 时通过提供 DML_CREATE_DEVICE_FLAG_DEBUG 来启用 DirectML 调试层。
启用 DirectML 调试层之后,任何 DirectML 错误或无效 API 调用都会导致调试信息以调试输出形式发出。 下面是一个示例。
DML_OPERATOR_CONVOLUTION: invalid D3D12_HEAP_TYPE. DirectML requires all bound buffers to be D3D12_HEAP_TYPE_DEFAULT.
直至 DML_FEATURE_LEVEL_5_2,要求必须启用 Direct3D 12 调试层才能启用 DirectML 调试层。 在早期版本的 DirectML 中,如果在标志中指定了 DML_CREATE_DEVICE_FLAG_DEBUG 标志,并且未安装调试层,则 DMLCreateDevice 将返回 DXGI_ERROR_SDK_COMPONENT_MISSING。 在较新版本的 DirectML 中,当 ID3D12InfoQueue 不可用时,消息将发送到 OutputDebugStringA。
代码示例
以下代码演示了仅为调试版本同时启用 Direct3D 12 和 DirectML 调试层。
// By default, disable the DirectML debug layer.
DML_CREATE_DEVICE_FLAGS dmlCreateDeviceFlags = DML_CREATE_DEVICE_FLAG_NONE;
#if defined(_DEBUG)
// If the project is in a debug build, then enable the Direct3D 12 debug layer.
// This is optional (starting in DML_FEATURE_LEVEL_5_2) but strongly recommended!
Microsoft::WRL::ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
debugController->EnableDebugLayer();
}
// If the project is in a debug build, then enable debugging via DirectML debug layers with this flag.
dmlCreateDeviceFlags |= DML_CREATE_DEVICE_FLAG_DEBUG;
#endif
// Create the DirectML device.
Microsoft::WRL::ComPtr<IDMLDevice> dmlDevice;
THROW_IF_FAILED(DMLCreateDevice(
d3D12Device.Get(),
dmlCreateDeviceFlags,
IID_PPV_ARGS(&dmlDevice));