使用 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 复制到项目输出文件夹。 但是,如果不使用调试层,可以考虑在发布版本中省略复制调试层。

Visual Studio 中的可再发行调试层

启用 Direct3D 12 调试层

Direct3D 12d3d12sdklayers.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));

另请参阅