使用 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.dllDirectML.dll 放在应用程序的可执行文件旁边。

如果使用 Visual Studio 将 Microsoft.AI.DirectML 添加为 NuGet 包依赖项,该项目将在项目配置页中显示选项,以复制或跳过复制核心运行时和调试层库。 默认情况下,DirectML NuGet 包配置为始终将这两个 DLL 复制到项目输出文件夹。 但是,如果不使用调试层,可能需要跳过在发行版本中复制调试层的操作。

Redistributable Debug Layer in Visual Studio

启用 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));

另请参阅