使用英语阅读

通过


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

另请参阅