cuFFT API 参考

cuFFT(CUDA 快速傅里叶变换库)的 API 参考指南。

1. 介绍

cuFFT 发行说明: CUDA 工具包发行说明

cuFFT GitHub 示例: CUDA 库示例

Nvidia 开发者论坛: GPU 加速库

提供反馈: Math-Libs-Feedback@nvidia.com

相关 FFT 库:

相关的 cuFFT 博客文章和 GTC 演示文稿:

本文档介绍了 NVIDIA® CUDA® 快速傅里叶变换 (FFT) 产品 cuFFT。它由两个独立的库组成:cuFFT 和 cuFFTW。cuFFT 库旨在为 NVIDIA GPU 提供高性能。cuFFTW 库作为移植工具提供,使 FFTW 用户能够以最少的工作量开始使用 NVIDIA GPU。

FFT 是一种分而治之的算法,用于高效计算复数或实值数据集的离散傅里叶变换。它是计算物理学和通用信号处理中最重要和广泛使用的数值算法之一。cuFFT 库提供了一个简单的接口,用于在 NVIDIA GPU 上计算 FFT,使用户能够在一个高度优化和经过测试的 FFT 库中快速利用 GPU 的浮点运算能力和并行性。

cuFFT 产品高效地支持 NVIDIA GPU 上各种各样的 FFT 输入和选项。此版本的 cuFFT 库支持以下功能

  • 针对可以写成 \(2^{a} \times 3^{b} \times 5^{c} \times 7^{d}\) 形式的输入大小高度优化的算法。一般来说,质因数越小,性能越好,即,二的幂次最快。

  • 适用于每个输入数据大小的 \(O\left( n\log n \right)\) 算法

  • 半精度(16 位浮点)、单精度(32 位浮点)和双精度(64 位浮点)。较低精度的变换具有更高的性能。

  • 复数和实值输入和输出。实值输入或输出比复数值需要更少的计算和数据,并且通常具有更快的解决方案时间。支持的类型有

    • C2C - 复数输入到复数输出

    • R2C - 实数输入到复数输出

    • C2R - 对称复数输入到实数输出

  • 1D、2D 和 3D 变换

  • 同时执行多个 1D、2D 和 3D 变换。这些批量变换比单个变换具有更高的性能。

  • 原位和异位变换

  • 任意维度内和维度间元素步幅(步幅布局)

  • FFTW 兼容的数据布局

  • 跨多个 GPU 执行变换

  • 流式执行,实现异步计算和数据移动

cuFFTW 库提供 FFTW3 API 以方便现有 FFTW 应用程序的移植。

请注意,从 CUDA 11.0 开始,最低支持的 GPU 架构是 SM35。请参阅 弃用的功能

2. 使用 cuFFT API

本章提供 cuFFT 库 API 的一般概述。有关特定功能的更完整信息,请参阅 cuFFT API 参考。鼓励用户在继续阅读更详细的描述之前阅读本章。

离散傅里叶变换 (DFT) 将复数值向量 \(x_{k}\)时域)映射到其频域表示,由下式给出

\(X_{k} = \sum\limits_{n = 0}^{N - 1}x_{n}e^{-2\pi i\frac{kn}{N}}\)

其中 \(X_{k}\) 是大小相同的复数值向量。这被称为正向 DFT。如果 e 的指数符号更改为正号,则变换为逆向变换。根据 \(N\) 的不同,将部署不同的算法以获得最佳性能。

cuFFT API 仿照 FFTW 建模,FFTW 是最流行和高效的基于 CPU 的 FFT 库之一。cuFFT 提供了一个名为计划的简单配置机制,该机制使用内部构建块来优化给定配置和所选特定 GPU 硬件的变换。然后,当调用执行函数时,实际变换将按照执行计划进行。这种方法的优势在于,一旦用户创建了计划,库就会保留执行计划多次所需的任何状态,而无需重新计算配置。此模型非常适用于 cuFFT,因为不同类型的 FFT 需要不同的线程配置和 GPU 资源,并且计划接口提供了一种重用配置的简单方法。

使用 cuFFT 计算数量为 BATCH 的大小为 NX 的一维 DFT 通常看起来像这样

#define NX 256
#define BATCH 10
#define RANK 1
...
{
    cufftHandle plan;
    cufftComplex *data;
    ...
    cudaMalloc((void**)&data, sizeof(cufftComplex)*NX*BATCH);
    cufftPlanMany(&plan, RANK, NX, &iembed, istride, idist,
        &oembed, ostride, odist, CUFFT_C2C, BATCH);
    ...
    cufftExecC2C(plan, data, data, CUFFT_FORWARD);
    cudaDeviceSynchronize();
    ...
    cufftDestroy(plan);
    cudaFree(data);
}

2.1. 访问 cuFFT

cuFFT 和 cuFFTW 库以共享库的形式提供。它们由编译好的程序组成,用户可以使用编译器和链接器将其合并到应用程序中。cuFFT 可以从 https://developer.nvidia.com/cufft 下载。通过选择下载 CUDA 生产版本,所有用户都能够安装包含 CUDA 工具包、SDK 代码示例和开发驱动程序的软件包。CUDA 工具包包含 cuFFT,示例包括 simplecuFFT

simplecuFFT 的 Linux 版本假定根安装目录为 /usr/local/cuda,并且产品的所在位置包含在其中,如下所示。根据您的系统修改 Makefile。

产品

位置和名称

包含文件

nvcc 编译器

/bin/nvcc

cuFFT

{lib, lib64}/libcufft.so

inc/cufft.h

带有 Xt 功能的 cuFFT

{lib, lib64}/libcufft.so

inc/cufftXt.h

cuFFTW

{lib, lib64}/libcufftw.so

inc/cufftw.h

最常见的情况是开发人员修改现有的 CUDA 例程(例如,filename.cu)以调用 cuFFT 例程。在这种情况下,应将包含文件 cufft.hcufftXt.h 插入到 filename.cu 文件中,并将库包含在链接行中。单个编译和链接行可能显示为

  • /usr/local/cuda/bin/nvcc [options] filename.cu -I/usr/local/cuda/inc -L/usr/local/cuda/lib -lcufft

当然,通常会有许多编译行,并且编译器 g++ 可以用于链接,只要库路径设置正确即可。

FFTW 接口的用户(请参阅 cuFFT 的 FFTW 接口)应包含 cufftw.h 并链接 cuFFT 和 cuFFTW 库。

cuFFT 和 cuFFTW 库中的函数假定数据位于 GPU 可见内存中。这意味着由 cudaMalloccudaMallocHostcudaMallocManaged 分配或使用 cudaHostRegister 注册的任何内存都可以用作 cuFFT 和 cuFFTW 函数的输入、输出或计划工作区。为了获得最佳性能,输入数据、输出数据和计划工作区应驻留在设备内存中。

cuFFTW 库还支持非 GPU 可见的输入数据和输出数据。

2.2. 傅里叶变换设置

使用 cuFFT 库的第一步是使用以下方法之一创建计划

  • cufftPlan1D() / cufftPlan2D() / cufftPlan3D() - 分别为 1D/2D/3D 变换创建简单计划。

  • cufftPlanMany() - 创建支持批量输入和步幅数据布局的计划。

  • cufftXtMakePlanMany() - 创建支持任何支持精度的批量输入和步幅数据布局的计划。

在计划创建函数中,cufftPlanMany() 允许使用更复杂的数据布局和批量执行。特定大小和类型的变换的执行可能需要几个处理阶段。当生成变换计划时,cuFFT 会推导出需要采取的内部步骤。这些步骤可能包括多次内核启动、内存复制等等。此外,所有中间缓冲区分配(在 CPU/GPU 内存上)都在计划期间发生。缓冲区在计划销毁时释放。在最坏的情况下,cuFFT 库为单精度和双精度变换分别分配 8*batch*n[0]*..*n[rank-1] cufftComplexcufftDoubleComplex 元素(其中 batch 表示将并行执行的变换数量,rank 是输入数据的维度数(请参阅 多维变换),n[] 是变换维度数组)的空间。根据计划的配置,可能会使用更少的内存。在某些特定情况下,临时空间分配可以低至 1*batch*n[0]*..*n[rank-1] cufftComplexcufftDoubleComplex 元素。临时空间在创建时为每个单独的计划单独分配(即,临时空间在计划之间不共享)。

使用库的下一步是调用执行函数,例如 cufftExecC2C()(请参阅 参数 cufftType),它将使用计划时定义的规范执行变换。

可以创建一个 cuFFT 计划,并通过提供不同的输入和输出指针在不同的数据集上执行多个变换。一旦不再需要该计划,应调用 cufftDestroy() 函数以释放为该计划分配的资源。

2.2.1. 可用内存需求

对任何 cuFFT 函数的第一次程序调用都会导致 cuFFT 内核的初始化。如果 GPU 上没有足够的可用内存,则可能会失败。建议首先初始化 cufft(例如,通过创建计划),然后再分配内存。

2.2.2. 计划初始化时间

在计划初始化期间,cuFFT 执行一系列步骤,包括启发式方法,以确定要使用的内核以及内核模块加载。从 CUDA 12.0 开始,cuFFT 使用 CUDA 并行线程执行汇编形式(PTX 代码)而不是二进制形式(cubin 对象)交付更大一部分内核。当初始化 cuFFT 计划时,cuFFT 内核的 PTX 代码由 CUDA 设备驱动程序在运行时加载并进一步编译为二进制代码。这称为即时 (JIT) 编译

JIT 编译会稍微增加 cuFFT 计划初始化时间,具体取决于变换大小和主机 CPU 的速度(请参阅 模块加载驱动程序 API)。但是,JIT 开销仅在计划初始化期间首次使用 计划创建函数之一生成二进制代码时发生。设备驱动程序自动缓存生成的二进制代码的副本,以避免在后续调用中重复编译。如有必要,可以自定义 CUDA_CACHE_PATHCUDA_CACHE_MAXSIZE 以设置缓存文件夹和最大大小(有关详细信息,请参阅 CUDA 环境变量),但默认设置通常没问题。

2.3. 傅里叶变换类型

除了通用的复数到复数 (C2C) 变换之外,cuFFT 还高效地实现了另外两种类型:实数到复数 (R2C) 和复数到实数 (C2R)。在许多实际应用中,输入向量是实值的。可以很容易地证明,在这种情况下,输出满足厄米对称性(\(X_{k} = X_{N - k}^{\ast}\),其中星号表示复共轭)。反之亦然:对于复厄米输入,逆变换将是纯实值的。cuFFT 利用这种冗余,仅处理厄米向量的前半部分。

单精度和双精度的变换执行函数分别定义为

  • cufftExecC2C() / cufftExecZ2Z() - 用于单/双精度的复数到复数变换。

  • cufftExecR2C() / cufftExecD2Z() - 用于单/双精度的实数到复数正向变换。

  • cufftExecC2R() / cufftExecZ2D() - 用于单/双精度的复数到实数逆变换。

这些函数中的每一个都需要不同的输入数据布局(有关详细信息,请参阅 数据布局)。

注意

复数到实数 (C2R) 变换接受复厄米输入。对于一维信号,这要求第 0 个元素(以及当 N 为偶数时,第 \(\frac{N}{2}\) 个输入)是实值的,即其虚部应为零。对于 d 维信号,这意味着 \(x_{(n_{1},n_{2},\ldots,n_{d})} = x_{(N_{1} - n_{1},N_{2} - n_{2},\ldots,N_{d} - n_{d})}^{\ast}\)。否则,变换的行为是未定义的。另请参阅 多维变换

函数 cufftXtExec()cufftXtExecDescriptor() 可以对任何支持的类型执行变换。

2.3.1. 半精度 cuFFT 变换

半精度变换有以下限制

  • 最低 GPU 架构为 SM_53

  • 大小仅限于二的幂次

  • 不支持实数到复数和复数到实数变换的实部步幅

  • 不支持多个 GPU

  • 不支持跨越超过 40 亿个元素的变换

有关计划创建详细信息,请参阅 cufftXtMakePlanMany 函数。

CUDA 工具包提供了 cuda_fp16.h 头文件,其中包含用于处理半精度算术的类型和内在函数。

2.3.2. Bfloat16 精度 cuFFT 变换

cuFFT 支持使用 nv_bfloat16 数据类型的 bfloat16 精度。请注意,cuFFT 在以 bfloat16 精度计算 FFT 时,利用了单精度和 bfloat16 精度算术运算的组合。Bfloat16 精度变换与半精度变换具有类似的限制

  • 最低 GPU 架构为 SM_80

  • 大小仅限于二的幂次

  • 不支持实数到复数和复数到实数变换的实部步幅

  • 不支持多个 GPU

  • 不支持跨越超过 40 亿个元素的变换

有关计划创建详细信息,请参阅 cufftXtMakePlanMany 函数。

CUDA 工具包提供了 cuda_bf16.h 头文件,其中包含用于处理 bfloat16 精度算术的类型和内在函数。

2.4. 数据布局

在 cuFFT 库中,数据布局严格取决于配置和变换类型。在通用复数到复数变换的情况下,输入和输出数据都应分别为单精度和双精度模式下的 cufftComplex/cufftDoubleComplex 数组。在 C2R 模式下,只需要非冗余复数元素的输入数组 \((x_{1},x_{2},\ldots,x_{\lfloor\frac{N}{2}\rfloor + 1})\)。输出数组 \((X_{1},X_{2},\ldots,X_{N})\) 在此模式下由 cufftReal/cufftDouble 元素组成。最后,R2C 需要一个实数值的输入数组 \((X_{1},X_{2},\ldots,X_{N})\),并返回一个非冗余复数元素的数组 \((x_{1},x_{2},\ldots,x_{\lfloor\frac{N}{2}\rfloor + 1})\)

在实数到复数和复数到实数变换中,输入数据的大小和输出数据的大小不同。对于异位变换,会创建一个单独的适当大小的数组。对于原位变换,用户应使用 padded 数据布局。此布局与 FFTW 兼容。

padded 布局中,输出信号从与输入数据相同的内存地址开始。因此,实数到复数的输入数据和复数到实数的输出数据必须填充。

下表总结了 1-d 变换的输入/输出数据的预期大小

FFT 类型

输入数据大小

输出数据大小

C2C

\(x\)cufftComplex

\(x\)cufftComplex

C2R

\(\left\lfloor \frac{x}{2} \right\rfloor + 1\)cufftComplex

\(x\)cufftReal

R2C*

\(x\)cufftReal

\(\left\lfloor \frac{x}{2} \right\rfloor + 1\)cufftComplex

实数到复数变换隐含地是正向变换。对于需要 FFTW 兼容输出的原位实数到复数变换,输入大小必须填充为 \(\left( {\lfloor\frac{N}{2}\rfloor + 1} \right)\) 复数元素。对于异位变换,输入和输出大小分别与逻辑变换大小 \(N\) 和非冗余大小 \(\lfloor\frac{N}{2}\rfloor + 1\) 匹配。

复数到实数变换隐含地是逆变换。对于选择 FFTW 兼容输出(默认填充模式)的原位复数到实数 FFT,假定输入大小为 \(\lfloor\frac{N}{2}\rfloor + 1\)cufftComplex 元素。请注意,当选择非单位输入和输出步幅时,原位复数到实数 FFT 可能会覆盖任意虚部输入点值。异位复数到实数 FFT 将始终覆盖输入缓冲区。对于异位变换,输入和输出大小分别与逻辑变换非冗余大小 \(\lfloor\frac{N}{2}\rfloor + 1\) 和大小 \(N\) 匹配。

2.5. 多维变换

多维 DFT 映射 \(d\) 维数组 \(x_{\mathbf{n}}\),其中 \(\mathbf{n} = (n_{1},n_{2},\ldots,n_{d})\) 到其频域数组,由下式给出

\(X_{\mathbf{k}} = \sum\limits_{n = 0}^{N - 1}x_{\mathbf{n}}e^{-2\pi i\frac{\mathbf{k}\mathbf{n}}{\mathbf{N}}}\)

其中 \(\frac{\mathbf{n}}{\mathbf{N}} = (\frac{n_{1}}{N_{1}},\frac{n_{2}}{N_{2}},\ldots,\frac{n_{d}}{N_{d}})\),求和表示嵌套求和集

\(\sum\limits_{n_{1} = 0}^{N_{1} - 1}\sum\limits_{n_{2} = 0}^{N_{2} - 1}\ldots\sum\limits_{n_{d} = 0}^{N_{d} - 1}\)

cuFFT 支持一维、二维和三维变换,所有这些变换都可以通过相同的 cufftExec* 函数调用(请参阅 傅里叶变换类型)。

与一维情况类似,实值输入数据的频域表示满足厄米对称性,定义为:\(x_{(n_{1},n_{2},\ldots,n_{d})} = x_{(N_{1} - n_{1},N_{2} - n_{2},\ldots,N_{d} - n_{d})}^{\ast}\)

C2R 和 R2C 算法利用这一事实,仅对信号数组的一半元素进行操作,即:\(x_{\mathbf{n}}\),对于 \(\mathbf{n} \in \{ 1,\ldots,N_{1}\} \times \ldots \times \{ 1,\ldots,N_{d - 1}\} \times \{ 1,\ldots,\lfloor\frac{N_{d}}{2}\rfloor + 1\}\)

数据布局中描述的数据对齐的一般规则适用于更高维度的变换。下表总结了多维 DFT 的输入和输出数据大小

维度

FFT 类型

输入数据大小

输出数据大小

1D

C2C

C2R

C2R

1D

C2R

\(\lfloor\frac{\mathbf{N}_{1}}{2}\rfloor + 1\)cufftComplex

R2C

1D

\(\mathbf{N}_{1}\)cufftReal

R2C

\(\lfloor\frac{\mathbf{N}_{1}}{2}\rfloor + 1\)cufftComplex

2D

C2C

C2R

C2R

2D

C2R

\(\mathbf{N}_{1}(\lfloor\frac{\mathbf{N}_{2}}{2}\rfloor + 1)\)cufftComplex

R2C

2D

\(\mathbf{N}_{1}\)cufftReal

R2C

\(\mathbf{N}_{1}(\lfloor\frac{\mathbf{N}_{2}}{2}\rfloor + 1)\)cufftComplex

3D

C2C

C2R

C2R

3D

C2R

\(\mathbf{N}_{1}\mathbf{N}_{2}(\lfloor\frac{\mathbf{N}_{3}}{2}\rfloor + 1)\)cufftComplex

R2C

3D

\(\mathbf{N}_{1}\)cufftReal

R2C

\(\mathbf{N}_{1}\mathbf{N}_{2}(\lfloor\frac{\mathbf{N}_{3}}{2}\rfloor + 1)\)cufftComplex

例如,用于异位实数到复数变换输出的三维数组的静态声明将如下所示

cufftComplex odata[N1][N2][N3/2+1];

2.6. 高级数据布局

高级数据布局功能允许仅转换输入数组的子集,或仅输出到较大数据结构的一部分。可以通过调用函数来设置

cufftResult cufftPlanMany(cufftHandle *plan, int rank, int *n, int *inembed,
    int istride, int idist, int *onembed, int ostride,
    int odist, cufftType type, int batch);

传递设置为 NULLinembedonembed 是一种特殊情况,等效于为每个传递 n。这与基本数据布局相同,其他高级参数(如 istride)将被忽略。

如果要使用高级参数,则必须正确指定所有高级接口参数。高级参数以相关数据类型(cufftRealcufftDoubleRealcufftComplexcufftDoubleComplex)的单位定义。

高级布局可以被视为输入/输出数据数组访问之上的额外抽象层。批量中信号编号 b 中坐标为 [z][y][x] 的元素将与内存中的以下地址关联

  • 1D

    input[ b * idist + x * istride ]

    output[ b * odist + x * ostride ]

  • 2D

    input[ b * idist` + (x * inembed[1] + y) * istride ]

    output[ b * odist + (x * onembed[1] + y) * ostride ]

  • 3D

    input[ b * idist + ((x * inembed[1] + y) * inembed[2] + z) * istride ]

    output[ b * odist + ((x * onembed[1] + y) * onembed[2] + z) * ostride ]

istrideostride 参数分别表示最不显著(即最内层)维度中两个连续输入和输出元素之间的距离。在单个 1D 变换中,如果要使用每个输入元素进行变换,则应将 istride 设置为 \(1\);如果要使用每隔一个输入元素进行变换,则应将 istride 设置为 \(2\)。 类似地,在单个 1D 变换中,如果希望紧凑地连续输出最终元素,则应将 ostride 设置为 \(1\);如果希望在最不显著的维度输出数据之间留有间距,则应将 ostride 设置为元素之间的距离。

inembedonembed 参数分别定义了输入数组和输出数组中每个维度的元素数量。inembed[rank-1] 包含输入数据最不显著(最内层)维度中元素的数量,不包括 istride 元素;输入数组最不显著维度中的元素总数然后为 istride*inembed[rank-1]inembed[0]onembed[0] 对应于最显著(即最外层)维度,并且实际上被忽略,因为 idistodist 参数会提供此信息。 请注意,变换的每个维度的大小应小于或等于相应维度的 inembedonembed 值,即 n[i]inembed[i]n[i]onembed[i],其中 \(i \in \{ 0,\ldots,rank - 1\}\)

idistodist 参数指示输入和输出数据中两个连续批次的第一个元素之间的距离。

2.7. 流式 cuFFT 变换

每个 cuFFT 计划都可以与 CUDA 流关联。 一旦关联,该计划内部阶段的所有启动都将通过指定的流进行。 cuFFT 执行的流式处理允许变换和内存复制之间可能存在重叠。(有关流的更多信息,请参阅《NVIDIA CUDA 编程指南》。)如果计划未与任何流关联,则启动将在默认 CUDA 流 stream(0) 中进行。 请注意,许多计划执行需要多次内核启动。

cuFFT 在内部使用私有流来对操作进行排序,包括事件同步。 cuFFT 不保证内部操作的顺序,并且顺序仅相对于用户设置的流保留。

从 CUDA 11.2 (cuFFT 10.4.0) 开始,在多 GPU 情况下支持 cufftSetStream()。 但是,当使用流时,对 cufftXtMemcpy() 的调用在多个 GPU 之间仍然是同步的。 在以前版本的 cuFFT 中,在多 GPU 情况下 cufftSetStream() 返回错误。 同样,在使用 cufftSetStream() 设置流后调用某些多 GPU 函数(例如 cufftXtSetCallback())将导致错误(有关更多详细信息,请参阅 API 函数)。

请注意,为了使用单个计划句柄重叠计划,用户需要管理工作区缓冲区。 每个并发计划执行都需要其独占工作区。 工作区可以通过 cufftSetWorkArea 函数设置。

2.8. 多 GPU cuFFT 变换

cuFFT 支持使用连接到 CPU 的最多十六个 GPU 来执行傅里叶变换,其计算分布在多个 GPU 上。 已定义 API,以允许用户编写新代码或修改现有代码以使用此功能。

某些现有函数(例如使用 cufftCreate() 创建计划)也适用于多 GPU 情况。 多 GPU 例程在其名称中包含 Xt

GPU 上的内存由辅助函数 cufftXtMalloc()/cufftXtFree()cufftXtMemcpy() 使用 cudaLibXtDesc 描述符进行管理。

性能是 GPU 之间的带宽、各个 GPU 的计算能力以及要执行的 FFT 的类型和数量的函数。 使用 NVLink 互连可获得最高性能 (https://www.nvidia.com/object/nvlink.html)。 第二好的选择是在 GPU 之间使用 PCI Express 3.0,并确保两个 GPU 都在同一个交换机上。 请注意,不能保证多 GPU 执行比单 GPU 执行在更短的时间内解决给定大小的问题。

cuFFT 的多 GPU 扩展构建在可扩展的 cuFFT API 之上。 使用此 API 定义和执行变换的一般步骤是

  • cufftCreate() - 创建一个空计划,与单 GPU 情况相同

  • cufftXtSetGPUs() - 定义要使用的 GPU

  • 可选:cufftEstimate{1d,2d,3d,Many}() - 估计所需工作区的大小。 这些是单 GPU 情况中使用的相同函数,尽管参数 workSize 的定义反映了使用的 GPU 数量。

  • cufftMakePlan{1d,2d,3d,Many}() - 创建计划。 这些是单 GPU 情况中使用的相同函数,尽管参数 workSize 的定义反映了使用的 GPU 数量。

  • 可选:cufftGetSize{1d,2d,3d,Many}() - 精细估计所需工作区的大小。 这些是单 GPU 情况中使用的相同函数,尽管参数 workSize 的定义反映了使用的 GPU 数量。

  • 可选:cufftGetSize() - 检查工作区大小。 这些是单 GPU 情况中使用的相同函数,尽管参数 workSize 的定义反映了使用的 GPU 数量。

  • 可选:cufftXtSetWorkArea() - 执行您自己的工作区分配。

  • cufftXtMalloc() - 在 GPU 上分配描述符和数据

  • cufftXtMemcpy() - 将数据复制到 GPU

  • cufftXtExecDescriptorC2C()/cufftXtExecDescriptorZ2Z() - 执行计划

  • cufftXtMemcpy() - 从 GPU 复制数据

  • cufftXtFree() - 释放使用 cufftXtMalloc() 分配的任何内存

  • cufftDestroy() - 释放 cuFFT 计划资源

2.8.1. 计划规范和工作区

在单 GPU 情况下,通过调用 cufftCreate(),然后调用 cufftMakePlan*() 来创建计划。 对于多 GPU,用于执行的 GPU 由调用 cufftXtSetGPUs() 标识,并且必须在调用 cufftCreate() 之后和调用 cufftMakePlan*() 之前发生。

请注意,当为单 GPU 调用 cufftMakePlan*() 时,工作区位于该 GPU 上。 在多 GPU 计划中,返回的工作区具有多个条目;每个 GPU 一个值。 也就是说,workSize 指向一个 size_t 数组,每个 GPU 一个条目。 此外,步幅和批次适用于与计划关联的所有 GPU 上的整个计划。

一旦计划被调用 cufftMakePlan*() 锁定,就可以在对 cufftXtExecDescriptor*() 的调用中指定不同的描述符,以在不同的数据集上执行计划,但新描述符必须以相同的顺序使用相同的 GPU。

与单 GPU 情况一样,cufftEstimateSize{Many,1d,2d,3d}()cufftGetSize{Many,1d,2d,3d}() 提供了多 GPU 计划所需工作区大小的估计值,在这种情况下,workSize 指向一个 size_t 数组,每个 GPU 一个条目。

类似地,由 cufftGetSize() 返回的实际工作区大小是一个 size_t 数组,在多 GPU 情况下,每个 GPU 一个条目。

2.8.2. 辅助函数

多 GPU cuFFT 执行函数假定某种数据布局,即在执行之前已将哪些输入数据复制到哪些 GPU,以及执行后哪些输出数据驻留在哪些 GPU 中。 cuFFT 提供了辅助用户在多个 GPU 上操作数据的函数。 这些函数必须在调用 cufftMakePlan*() 之后调用。

在单 GPU 上,用户可以调用 cudaMalloc()cudaFree() 来分配和释放 GPU 内存。 为了在多 GPU 情况下提供类似的功能,cuFFT 包括 cufftXtMalloc()cufftXtFree() 函数。 函数 cufftXtMalloc() 返回一个描述符,该描述符指定这些内存的位置。

在单 GPU 上,用户可以调用 cudaMemcpy() 以在主机和 GPU 内存之间传输数据。 为了在多 GPU 情况下提供类似的功能,cuFFT 包括 cufftXtMemcpy(),它允许用户在主机和多 GPU 内存之间甚至在 GPU 内存之间进行复制。

所有单 GPU cuFFT FFT 都以自然顺序返回输出数据,即结果的顺序与在数据上执行 DFT 的顺序相同。 一些快速傅里叶变换产生中间结果,其中数据以自然输出的排列形式保留。 当批次为 1 时,数据以自然输出的排列形式保留在 GPU 内存中。

当使用 cufftXtMemcpy() 将数据从 GPU 内存复制回主机内存时,无论 GPU 上的数据是自然顺序还是排列顺序,结果都将以自然顺序排列。 使用 CUFFT_COPY_DEVICE_TO_DEVICE 允许用户将单个变换后产生的排列数据格式复制到 GPU 上的自然顺序。

2.8.3. 在排列输入上进行多 GPU 2D 和 3D 变换

对于多 GPU 上的单个 2D 或 3D 变换,当 cufftXtMemcpy() 将数据分发到 GPU 时,数组在 X 轴上划分。 例如,对于两个 GPU,每个 GPU 复制一半 X 维度点,用于所有 Y(和 Z)值。 当计算变换时,数据被排列,使得它们在 Y 轴上划分。 也就是说,一半的 Y 维度点,用于所有 X(和 Z)值,都在每个 GPU 上。

当 cuFFT 为多 GPU 上的单个变换创建 2D 或 3D 计划时,它实际上会创建两个计划。 一个计划期望输入在 X 轴上划分。 另一个计划期望数据在 Y 轴上划分。 这样做是因为许多算法计算正向 FFT,然后在结果上执行一些逐点操作,然后计算逆 FFT。 内存复制以将数据恢复到原始顺序将是昂贵的。 为了避免这种情况,cufftXtMemcpycufftXtExecDescriptor() 会跟踪数据排序,以便使用正确的操作。

cuFFT 处理任一顺序数据的能力使以下序列成为可能。

  • cufftCreate() - 创建一个空计划,与单 GPU 情况相同

  • cufftXtSetGPUs() - 定义要使用的 GPU

  • cufftMakePlan{1d,2d,3d,Many}() - 创建计划。

  • cufftXtMalloc() - 在 GPU 上分配描述符和数据

  • cufftXtMemcpy() - 将数据复制到 GPU

  • cufftXtExecDescriptorC2C()/cufftXtExecDescriptorZ2Z() - 计算正向 FFT

  • userFunction() - 修改频域中的数据

  • cufftXtExecDescriptorC2C()/cufftXtExecDescriptorZ2Z() - 计算逆 FFT

  • 请注意,在执行调用之间不需要复制/排列数据

  • cufftXtMemcpy() - 将数据复制到主机

  • cufftXtFree() - 释放使用 cufftXtMalloc() 分配的任何内存

  • cufftDestroy() - 释放 cuFFT 计划资源

2.8.4. 支持的功能

从 cuFFT 版本 7.0 开始,多 GPU 执行支持单 GPU 功能的子集。

要求和限制

  • 所有 GPU 必须具有相同的 CUDA 架构级别并支持统一虚拟地址空间。

  • 在 Windows 上,GPU 板卡必须在 Tesla Compute Cluster (TCC) 模式下运行。

  • 对于使用 CUDA Driver API 的应用程序,在多个 GPU 上运行 cuFFT 仅与在每个 GPU 上使用主上下文的应用程序兼容。

  • 不支持步幅输入和输出。

  • 仅在具有 NVLink 的机器上支持在超过 8 个 GPU 上运行 cuFFT(最多 16 个 GPU)。

虽然批次计数大于 1 的变换不会施加额外的约束,但批次计数为 1 的变换有一些限制。 单批次 FFT 仅支持就地模式,并且根据 FFT 类型具有额外的约束。 此行为在下表中进行了总结

batch=1

1D

2D

3D

C2C/Z2Z

  • 2,4,8,16 个 GPU

  • 仅限 2 的幂大小

  • 2-4 个 GPU 的最小大小为 64

  • 8 个 GPU 的最小大小为 128

  • 16 个 GPU 的最小大小为 1024

  • 2-16 个 GPU

  • 每个维度都满足以下条件之一

    • 维度必须分解为小于或等于 127 的素数

    • 单精度最大维度大小为 4096

    • 双精度最大维度大小为 2048

  • 最小大小为 32

  • 不支持 LTO 回调

R2C/D2Z

不支持

  • 2-16 个 GPU

  • 每个维度都满足以下条件之一

    • 维度必须分解为小于或等于 127 的素数

    • 单精度最大维度大小为 4096

    • 双精度最大维度大小为 2048

  • 最小大小为 32

  • 最快变化的维度大小需要为偶数

  • 仅支持 CUFFT_XT_FORMAT_INPLACE 输入描述符格式

  • 不支持旧版回调/LTO 回调

C2R/Z2D

不支持

  • 2-16 个 GPU

  • 每个维度都满足以下条件之一

    • 维度必须分解为小于或等于 127 的素数

    • 单精度最大维度大小为 4096

    • 双精度最大维度大小为 2048

  • 最小大小为 32

  • 最快变化的维度大小需要为偶数

  • 仅支持 CUFFT_XT_FORMAT_INPLACE_SHUFFLED 输入描述符格式

  • 不支持旧版回调/LTO 回调

一般准则是

  • cufftXtSetGPUs() 函数的参数 whichGPUs 确定了 GPU 相对于数据分解的顺序(第一个数据块放置在由 whichGPUs 的第一个元素指示的 GPU 上)

  • 整个变换的数据必须适合分配给它的 GPU 的内存中。

  • 对于 n 个 GPU 上的批次大小 m

    • m % n 个 GPU 执行 \(\left\lfloor \frac{m}{n} \right\rfloor+\ 1\) 个变换。

    • 其余 GPU 执行 \(\left\lfloor \frac{m}{n} \right\rfloor\) 个变换。

批次大小输出差异

单 GPU cuFFT 结果始终以自然顺序返回。 当使用多个 GPU 执行多个变换时,结果也以自然顺序返回。 当使用多个 GPU 执行单个变换时,结果以正常结果的排列形式返回,以减少通信时间。 此行为在下表中进行了总结

GPU 数量

变换数量

GPU 上的输出顺序

一个

一个或多个变换

自然顺序

多个

一个

排列结果

多个

多个

自然顺序

为了在 1D 单个变换情况下在 GPU 内存中生成自然顺序结果,需要使用 CUFFT_COPY_DEVICE_TO_DEVICE 调用 cufftXtMemcpy()

2D 和 3D 多 GPU 变换支持执行以排列顺序结果作为输入的变换。 在这种情况下执行后,输出将以自然顺序排列。 也可以将 cufftXtMemcpy()CUFFT_COPY_DEVICE_TO_DEVICE 一起使用,以将 2D 或 3D 数据返回到自然顺序。

有关单 GPU 和多 GPU 示例,请参阅 cuFFT 代码示例部分。

2.9. cuFFT 回调例程

回调例程是用户提供的内核例程,cuFFT 将在加载或存储数据时调用它们。 它们允许用户执行数据预处理或后处理,而无需额外的内核调用。

注意

在 CUDA 12.6 Update 2 中,我们引入了对链接时优化 (LTO) 回调的支持,以替代已弃用(旧版)的回调。 有关更多信息,请参阅 LTO 加载和存储回调例程

从 CUDA 11.4 开始,在所有 GPU 架构上,已弃用对使用单独编译的设备代码(即旧版回调)的回调功能的支持。 回调功能将继续在所有 GPU 架构上得到支持。

2.9.1. cuFFT 回调例程功能概述

cuFFT 提供了一组 API,允许 cuFFT 用户提供 CUDA 函数,这些函数在加载数据以进行 FFT 处理之前或在 FFT 完成后存储数据时,重定向或操作数据。 对于加载回调,cuFFT 调用回调例程输入数据的地址和要从设备内存加载的值的偏移量,回调例程返回它希望 cuFFT 改为使用的值。 对于存储回调,cuFFT 调用回调例程它已计算的值,以及输出数据的地址和要写入设备内存的值的偏移量,回调例程修改该值并存储修改后的结果。

为了向 cuFFT 提供回调,使用可扩展计划 API 创建计划。 在调用 cufftCreate 后,用户可以通过以下方式将加载回调例程或存储回调例程或两者都与计划关联:

  • cufftMakePlan 之前调用 cufftXtSetJITCallback,用于 LTO 回调

  • cufftMakePlan 之后调用 cufftXtSetCallback,用于旧版回调

调用者还可以选择指定设备指针,指向他们希望与计划关联的不透明结构。 此指针将由 cuFFT 库传递给回调例程。 调用者可以使用此结构来记住计划维度和步幅,或者拥有指向辅助数据的指针等。

在某些限制条件下,回调例程被允许请求共享内存供自己使用。 如果请求的共享内存量可用,则 cufft 将在调用回调例程时将指向它的指针传递给它。

CUFFT 允许 8 种类型的回调例程,每种类型对应于加载或存储、实数或复数、单精度或双精度的可能组合

  • 对于 LTO 回调,用户必须提供一个 LTO 例程,该例程与指定例程类型的函数原型匹配。 否则,计划函数 cufftMakePlan 将失败

  • 对于旧版回调,调用者有责任提供一个例程,该例程与指定例程类型的函数原型匹配。

如果计划句柄已关联指定类型的回调,则设置回调函数将用新的回调函数替换它。

cuFFT 的回调例程扩展构建在可扩展的 cuFFT API 之上。 使用回调定义和执行变换的一般步骤是

  • cufftCreate() - 创建一个空计划,与单 GPU 情况相同。

  • (对于 LTO 回调)cufftXtSetJITCallback() - 为此计划设置加载和/或存储 LTO 回调。

  • cufftMakePlan{1d,2d,3d,Many}() - 创建计划。 这些是单 GPU 情况中使用的相同函数。

  • (对于 旧版 回调)cufftXtSetCallback() - 为此计划设置加载和/或存储旧版回调。

  • cufftExecC2C() 等 - 执行计划。

  • cufftDestroy() - 释放 cuFFT 计划资源。

回调函数在维度大小无法分解为小于 127 的素数的变换中不受支持。 维度素因子仅限于 2、3、5 和 7 的计划上的回调函数可以安全地调用 __syncthreads()。 在其他计划上,结果未定义。

注意

LTO 回调 API 在 64 位 Windows 和 LINUX 操作系统上的动态和静态 cuFFT 库中可用。 LTO 回调 API 需要动态库路径中存在的兼容 nvJitLink 和 NVRTC 库。 有关更多详细信息,请参阅 LTO 加载和存储回调例程

旧版回调 API 仅在 64 位 LINUX 操作系统上的静态 cuFFT 库中可用。

2.9.2. LTO 加载和存储回调例程

给定工具包版本的 cuFFT 中的 LTO 回调需要使用来自同一工具包或更高版本,但在同一工具包主版本中的 nvJitLink 库

此外,为了为 LTO 回调例程指定自定义名称,cuFFT 需要使用 NVRTC 库。 cuFFT 使用 NVRTC 围绕用户回调编译最小包装器,并带有自定义符号名称。 提供给 cuFFT API 的自定义符号名称必须是有效的、以 null 结尾的 C 字符串,其中包含未损坏的名称;当前,更改符号名称范围的关键字(例如 namespace)或损坏(例如 extern "C")不受支持。

使用的 NVRTC 库必须来自工具包版本,该工具包版本与 nvJitLink 库的版本相同或更旧,并且两者都必须来自同一工具包主版本。

例如,在工具包版本 12.6 中,cuFFT 需要 nvJitLink 来自工具包版本 12.X,其中 X >= 6,而 NVRTC 来自工具包版本 12.Y,其中 0 <= Y <= X

nvJitLink 和 NVRTC 库都是动态加载的,应存在于系统的动态链接路径中(例如,Unix 系统上的 LD_LIBRARY_PATH 或 Windows 系统上的 PATH)。

LTO 回调的代码示例可在公共 CUDA 库示例 github 存储库中找到。

2.9.2.1. 指定 LTO 加载和存储回调例程

cuFFT 中 LTO 回调的使用分为两个部分

  • 生成 LTO 回调(即,将回调例程编译为 LTO-IR)。

  • 将 LTO 回调与 cuFFT 计划关联。

要生成 LTO 回调,用户可以使用 nvcc 和任何受支持的标志(例如 -dlto-gencode=arch=compute_XX,code=lto_XX,其中 XX 指示目标 GPU 架构)将回调设备函数编译为 LTO-IR;或者,用户可以使用 NVRTC 通过 -dlto 标志执行运行时编译来生成 LTO 回调。

请注意,PTX JIT 是 JIT LTO 内核最终确定轨迹的一部分,因此支持早于当前系统架构的架构;用户可以将他们的回调函数编译为目标架构 XX 的 LTO-IR,并在架构为 YY 的 GPU 上执行使用回调函数的计划,其中 XX <= YY。 请参阅 编译器对使用 nvJitLink 库进行运行时 LTO 的支持即时 (JIT) 编译 以获取更多详细信息。

例如,如果用户想要为 R2C 变换指定加载回调,他们可以编写以下代码

__device__  cufftReal myOwnLTOCallback(void *dataIn,
                                       unsigned long long offset,
                                       void *callerInfo,
                                       void *sharedPtr) {
    cufftReal ret;
    // use offset, dataIn, and optionally callerInfo to
    // compute the return value
    return ret;
}

要将回调编译为 LTO-IR,用户可以执行以下操作

# Compile the code to SM60 LTO-IR into a fatbin file
nvcc -gencode=arch=compute_60,code=lto_60 -dc -fatbin callback.cu -o callback.fatbin
#Turn the fatbin data into a C array inside a header, for easy inclusion in host code
bin2c --name my_lto_callback_fatbin --type longlong callback.fatbin > callback_fatbin.h

要关联 LTO 回调与 cuFFT 计划,用户可以利用新的 API 调用 cufftXtSetJITCallback(),它的工作方式与 cufftXtSetCallback() 类似,但有一些注意事项。

首先,cufftXtSetJITCallback() 必须在通过 cufftCreate() 创建计划之后,并在使用 cufftMakePlan*() 和类似例程调用计划初始化函数之前调用。

其次,目前不支持从计划中删除 LTO 回调(使用 cufftXtClearCallback())。必须创建一个新计划。

#include <cufftXt.h>
#include "callback_fatbin.h"

int main() {
   cufftResult status;
   cufftHandle fft_plan;
   ...

   status = cufftCreate(&fft_plan);

   // NOTE: LTO callbacks must be set before plan creation and cannot be unset (yet)
   size_t lto_callback_fatbin_size = sizeof(my_lto_callback_fatbin);
   status = cufftXtSetJITCallback(fft_plan, "myOwnLTOCallback", (void*)my_lto_callback_fatbin, lto_callback_fatbin_size, CUFFT_CB_LD_REAL, (void **)&device_params));
   status = cufftMakePlan1d(fft_plan, signal_size, CUFFT_C2R, batches, &work_size);
   ...
}

2.9.2.2. LTO 回调例程函数详细信息

以下是用户提供的 LTO 回调例程的函数原型,cuFFT 调用这些例程以在变换之前加载数据。

typedef  cufftComplex (*cufftJITCallbackLoadC)(void *dataIn,
                                              unsigned long long offset,
                                              void *callerInfo,
                                              void *sharedPointer);

typedef  cufftDoubleComplex (*cufftJITCallbackLoadZ)(void *dataIn,
                                                     unsigned long long offset,
                                                     void *callerInfo,
                                                     void *sharedPointer);

typedef  cufftReal (*cufftJITCallbackLoadR)(void *dataIn,
                                            unsigned long long offset,
                                            void *callerInfo,
                                            void *sharedPointer);

typedef  cufftDoubleReal (*cufftJITCallbackLoadD)(void *dataIn,
                                                  unsigned long long offset,
                                                  void *callerInfo,
                                                  void *sharedPointer);

所有 LTO 加载回调的参数定义如下

  • offset:输入元素相对于输入数据起点的偏移量。这不是字节偏移量,而是从数据起点开始的元素数量。

  • dataIn:设备指针,指向在 cufftExecute 调用中传入的输入数组的起点。

  • callerInfo:设备指针,指向在 cufftXtSetCallback 调用中传入的可选调用者指定数据。

  • sharedPointer:指向共享内存的指针,仅当用户调用了 cufftXtSetCallbackSharedSize() 时才有效。

以下是函数原型以及指向用户提供的 LTO 回调例程的指针的 typedef,cuFFT 调用这些例程以在变换完成后存储数据。请注意,存储回调函数不返回值。这是因为存储回调函数不仅负责按需变换数据,还负责将数据写入所需的位置。这允许存储回调重新排列数据,例如将零频率结果移到输出的中心。

typedef  void (*cufftJITCallbackStoreC)(void *dataOut,
                                        unsigned long long offset,
                                        cufftComplex element,
                                        void *callerInfo,
                                        void *sharedPointer);

typedef  void (*cufftJITCallbackStoreZ)(void *dataOut,
                                        unsigned long long offset,
                                        cufftDoubleComplex element,
                                        void *callerInfo,
                                        void *sharedPointer);

typedef  void (*cufftJITCallbackStoreR)(void *dataOut,
                                        unsigned long long offset,
                                        cufftReal element,
                                        void *callerInfo,
                                        void *sharedPointer);

typedef  void (*cufftJITCallbackStoreD)(void *dataOut,
                                        unsigned long long offset,
                                        cufftDoubleReal element,
                                        void *callerInfo,
                                        void *sharedPointer);

所有 LTO 存储回调的参数定义如下

  • offset:输出元素相对于输出数据起点的偏移量。这不是字节偏移量,而是从数据起点开始的元素数量。

  • dataOut:设备指针,指向在 cufftExecute 调用中传入的输出数组的起点。

  • element:CUFFT 为偏移量参数指定的元素计算的实数或复数结果。

  • callerInfo:设备指针,指向在 cufftXtSetCallback 调用中传入的可选调用者指定数据。

  • sharedPointer:指向共享内存的指针,仅当用户调用了 cufftXtSetCallbackSharedSize() 时才有效。

2.9.3. 旧式加载和存储回调例程

2.9.3.1. 指定旧式加载和存储回调例程

为了将旧式回调例程与计划关联,必须获取指向回调例程的设备指针。

例如,如果用户想要为 R2C 变换指定加载回调,他们将编写回调函数的设备代码,并定义一个全局设备变量,其中包含指向该函数的指针

__device__  cufftReal myOwnCallback(void *dataIn,
                                    size_t offset,
                                    void *callerInfo,
                                    void *sharedPtr) {
    cufftReal ret;
    // use offset, dataIn, and optionally callerInfo to
    // compute the return value
    return ret;
}
__device__ cufftCallbackLoadR myOwnCallbackPtr = myOwnCallback;

从主机端,用户然后必须获取旧式回调例程的地址,该地址存储在 myOwnCallbackPtr 中。这是通过 cudaMemcpyFromSymbol 完成的,如下所示

cufftCallbackLoadR hostCopyOfCallbackPtr;

cudaMemcpyFromSymbol(&hostCopyOfCallbackPtr,
                     myOwnCallbackPtr,
                     sizeof(hostCopyOfCallbackPtr));

hostCopyOfCallbackPtr 然后包含回调例程的设备地址,该地址应传递给 cufftXtSetCallback。请注意,对于多 GPU 变换,hostCopyOfCallbackPtr 将需要是指针数组,并且必须为每个 GPU 调用 cudaMemcpyFromSymbol。 请注意,由于对变量使用的限制,__managed__ 变量不适合传递给 cufftSetCallback(有关 __managed__ 变量的更多信息,请参阅NVIDIA CUDA 编程指南)。

2.9.3.2. 旧式回调例程函数详细信息

以下是函数原型以及指向用户提供的旧式回调例程的指针的 typedef,cuFFT 调用这些例程以在变换之前加载数据。

typedef  cufftComplex (*cufftCallbackLoadC)(void *dataIn,
                                            size_t offset,
                                            void *callerInfo,
                                            void *sharedPointer);

typedef  cufftDoubleComplex (*cufftCallbackLoadZ)(void *dataIn,
                                                  size_t offset,
                                                  void *callerInfo,
                                                  void *sharedPointer);

typedef  cufftReal (*cufftCallbackLoadR)(void *dataIn,
                                         size_t offset,
                                         void *callerInfo,
                                         void *sharedPointer);

typedef  cufftDoubleReal (*cufftCallbackLoadD)(void *dataIn,
                                               size_t offset,
                                               void *callerInfo,
                                               void *sharedPointer);

所有旧式加载回调的参数定义如下

  • offset:输入元素相对于输入数据起点的偏移量。这不是字节偏移量,而是从数据起点开始的元素数量。

  • dataIn:设备指针,指向在 cufftExecute 调用中传入的输入数组的起点。

  • callerInfo:设备指针,指向在 cufftXtSetCallback 调用中传入的可选调用者指定数据。

  • sharedPointer:指向共享内存的指针,仅当用户调用了 cufftXtSetCallbackSharedSize() 时才有效。

以下是函数原型以及指向用户提供的旧式回调例程的指针的 typedef,cuFFT 调用这些例程以在变换完成后存储数据。请注意,存储回调函数不返回值。这是因为存储回调函数不仅负责按需变换数据,还负责将数据写入所需的位置。这允许存储回调重新排列数据,例如将零频率结果移到输出的中心。

typedef  void (*cufftCallbackStoreC)(void *dataOut,
                                     size_t offset,
                                     cufftComplex element,
                                     void *callerInfo,
                                     void *sharedPointer);

typedef  void (*cufftCallbackStoreZ)(void *dataOut,
                                     size_t offset,
                                     cufftDoubleComplex element,
                                     void *callerInfo,
                                     void *sharedPointer);

typedef  void (*cufftCallbackStoreR)(void *dataOut,
                                     size_t offset,
                                     cufftReal element,
                                     void *callerInfo,
                                     void *sharedPointer);

typedef  void (*cufftCallbackStoreD)(void *dataOut,
                                     size_t offset,
                                     cufftDoubleReal element,
                                     void *callerInfo,
                                     void *sharedPointer);

所有旧式存储回调的参数定义如下

  • offset:输出元素相对于输出数据起点的偏移量。这不是字节偏移量,而是从数据起点开始的元素数量。

  • dataOut:设备指针,指向在 cufftExecute 调用中传入的输出数组的起点。

  • element:CUFFT 为偏移量参数指定的元素计算的实数或复数结果。

  • callerInfo:设备指针,指向在 cufftXtSetCallback 调用中传入的可选调用者指定数据。

  • sharedPointer:指向共享内存的指针,仅当用户调用了 cufftXtSetCallbackSharedSize() 时才有效。

2.9.4. cuFFT 回调例程功能的编码注意事项

cuFFT 支持所有类型的变换、维度、批次或元素之间步长的回调。单精度和双精度变换均支持回调。

cuFFT 支持范围广泛的参数,并基于给定计划的这些参数,尝试优化性能。启动的内核数量,以及每个内核的启动块数和每个块的线程数,将根据 cuFFT 分解变换的方式而有所不同。对于某些配置,cuFFT 将为每个线程加载或存储(和处理)多个输入或输出。对于某些配置,线程可以按任何顺序加载或存储输入或输出,并且 cuFFT 不保证给定线程处理的输入或输出是连续的。这些特性可能随变换大小、变换类型(例如 C2C 与 C2R)、维度数量和 GPU 架构而变化。这些变化也可能因库版本而异。

当使用多个内核来实现变换时,第一个内核(执行加载的内核)的线程和块结构通常与最后一个内核(执行存储的内核)的线程和块结构不同。

回调的一个常见用途是减少读取或写入内存的数据量,可以通过选择性过滤或通过类型转换来实现。当使用多个内核来实现变换时,cuFFT 交替使用工作区和输出缓冲区来写入中间结果。这意味着输出缓冲区必须始终足够大以容纳整个变换。

对于尺寸可以分解为 2、3、5 或 7 的幂的变换,cuFFT 保证它将从内核中的点调用加载和存储回调例程,在这些点从回调例程中调用 __syncthreads 函数是安全的。调用者负责保证回调例程位于回调代码已收敛的点,以避免死锁。对于尺寸分解为更高素数的计划,回调例程调用 __syncthreads 的结果未定义。

请注意,不保证网格内块的相对执行顺序。因此,回调不应依赖于内核内的任何特定顺序。例如,重新排序数据(例如 FFT 移位)可能依赖于块的执行顺序。在这种情况下,结果将是未定义的。

2.9.4.1. LTO 回调例程的编码注意事项

对于实数到复数 (R2C, D2Z) 和复数到复数 (C2C, Z2Z) 变换,cuFFT 将为输入中的每个点调用 LTO 加载回调例程一次且仅一次。与旧式回调不同,对于复数到实数 (C2R, Z2D) 变换,每个元素可能会多次调用 LTO 加载回调。输入值不会被更新两次(即,即使对于就地变换,变换后的值也将存储在寄存器中而不是内存中),但用户不应依赖于其回调设备函数中每个元素的调用次数。

与旧式回调类似,对于输出中的每个点,LTO 存储回调将被调用一次且仅一次。如果变换是就地完成的(即,输入和输出数据在同一内存位置),则给定元素的存储回调不能覆盖其他元素。它可以覆盖给定元素,也可以写入完全不同的输出缓冲区。

cuFFT 尚不支持多 GPU 变换的 LTO 回调。

2.9.4.2. 旧式回调例程的编码注意事项

cuFFT 支持任意数量 GPU 上的旧式回调。

对于输入中的每个点,cuFFT 将调用加载回调例程一次且仅一次。类似地,对于输出中的每个点,它将调用存储回调例程一次且仅一次。如果变换是就地完成的(即,输入和输出数据在同一内存位置),则给定元素的存储回调不能覆盖其他元素。它可以覆盖给定元素,也可以写入完全不同的输出缓冲区。

对于多 GPU 变换,传递给回调例程的索引是该 GPU 上数据起点的元素索引,而不是整个输入或输出数据数组起点的元素索引。

2.10. 线程安全

只要不同的主机线程使用不同的计划执行 FFT,并且输出数据是不相交的,cuFFT API 就是线程安全的。

2.11. CUDA 图形支持

单 GPU 计划支持将 CUDA 图形 与 cuFFT 一起使用。从 cuFFT 版本 10.4.0 开始,多 GPU 计划也支持它。与 cuFFT 计划关联的流必须满足 使用流捕获创建图形 中所述的要求。

注意

从 CUDA 11.8(包括 CUDA 12.0 及更高版本)开始,不再支持在异地模式变换中加载数据的旧式回调例程的 CUDA 图形。从 CUDA 12.6 Update 2 开始,LTO 回调可以用作旧式回调的替代品,而没有此限制。cuFFT 在 cuFFT 11.4 中弃用了基于单独编译的设备代码(旧式回调)的回调功能。

2.12. 静态库和回调支持

从 6.5 版本开始,cuFFT 库也以静态形式作为 Linux 和 Mac 上的 libcufft_static.a 和 libcufftw_static.a 提供。Windows 上不支持静态库。静态 cufft 和 cufftw 库依赖于线程抽象层库 libculibos.a

例如,在 Linux 上,要使用 cuFFT 针对动态库编译一个小型应用程序,可以使用以下命令

nvcc mCufftApp.c  -lcufft  -o myCufftApp

对于 Linux 上的 cufftw,要针对动态库编译一个小型应用程序,可以使用以下命令

nvcc mCufftwApp.c  -lcufftw  -lcufft  -o myCufftwApp

而要针对静态 cuFFT 库进行编译,则需要采取额外的步骤。库需要进行设备链接。它可能发生在简单程序的构建和链接期间,或者作为单独的步骤。整个过程在 在 CUDA 中使用单独编译 中进行了描述。

对于版本 9.0 或更高版本中的 cuFFT 和 cufftw,可以使用任何受支持的架构来执行设备链接

静态 cuFFT 编译命令

nvcc mCufftApp.c  -lcufft_static   -lculibos -o myCufftApp

静态 cufftw 编译命令

nvcc mCufftwApp.c   -lcufftw_static  -lcufft_static   -lculibos  -o myCufftwApp

在版本 9.0 之前,正确的链接需要指定受支持架构的子集,如下列命令所示

静态 cuFFT 编译命令

nvcc mCufftApp.c  -lcufft_static   -lculibos -o myCufftApp\
    -gencode arch=compute_20,\"code=sm_20\"\
    -gencode arch=compute_30,\"code=sm_30\"\
    -gencode arch=compute_35,\"code=sm_35\"\
    -gencode arch=compute_50,\"code=sm_50\"\
    -gencode arch=compute_60,\"code=sm_60\"\
    -gencode arch=compute_60,\"code=compute_60\"

静态 cufftw 编译命令

nvcc mCufftwApp.c    -lcufftw_static  -lcufft_static   -lculibos  -o myCufftwApp\
    -gencode arch=compute_20,\"code=sm_20\"\
    -gencode arch=compute_30,\"code=sm_30\"\
    -gencode arch=compute_35,\"code=sm_35\"\
    -gencode arch=compute_50,\"code=sm_50\"\
    -gencode arch=compute_60,\"code=sm_60\"\
    -gencode arch=compute_60,\"code=compute_60\"

请注意,cuFFT 库可能不包含某些架构的代码,只要存在较低架构的二进制兼容代码(例如 SM52、SM61)即可。这反映在上面的链接命令中,并且在使用 r9.0 之前的版本时非常重要。要确定 cuFFT 库中是否包含特定的 SM,可以使用 cuobjdump 实用程序。例如,如果您想知道是否包含 SM_50,则要运行的命令是 cuobjdump -arch sm_50 libcufft_static.a。某些内核仅在选定的架构上构建(例如,具有半精度算术的内核仅适用于 SM53 及更高版本)。这可能会导致链接时出现警告,指出这些内核缺少架构。这些警告可以安全地忽略。

也可以使用本机 Host C++ 编译器并作为单独的步骤执行设备链接。有关更多详细信息,请查阅 NVCC 文档。根据 Host 操作系统,链接行可能需要一些额外的库,例如 pthreaddl

请注意,在这种情况下,不需要库 cuda。如果需要,CUDA 运行时将尝试显式打开 cuda 库。对于未安装 CUDA 驱动程序的系统,这允许应用程序优雅地管理此问题,并在 CPU 专用路径可用时可能运行。

cuFFT 静态库支持用户提供的旧式回调例程。旧式回调例程是 CUDA 设备代码,必须使用 NVCC 单独编译并与 cuFFT 库链接。有关详细信息,请参阅有关单独编译的 NVCC 文档。如果您在编译回调函数时指定 SM,则必须指定 cuFFT 包含的 SM 之一。

2.12.1. 不带旧式回调支持的静态库

从 cuFFT 版本 9.2 开始,添加了 cuFFT 静态库的新变体 libcufft_static_nocallback.a。这个新版本不包含旧式回调功能,可以使用主机编译器链接。

2.13. 准确性和性能

DFT 可以实现为矩阵向量乘法,需要 \(O(N^{2})\) 次运算。然而,cuFFT 库采用 Cooley-Tukey 算法 来减少所需运算的次数,以优化特定变换大小的性能。此算法将 DFT 矩阵表示为稀疏构建块矩阵的乘积。cuFFT 库实现了以下构建块:radix-2、radix-3、radix-5 和 radix-7。因此,cuFFT 库优化了任何可以分解为 \(2^{a} \times 3^{b} \times 5^{c} \times 7^{d}\) (其中 abcd 是非负整数)的变换大小的性能。还有用于其他素数 m 的 radix-m 构建块,其值 < 128。当长度不能分解为 2 到 127 的素数的幂的倍数时,将使用 Bluestein 算法。由于 Bluestein 实现比 Cooley-Tukey 实现需要更多的每次输出点计算,因此 Cooley-Tukey 算法的准确性更好。纯 Cooley-Tukey 实现具有出色的准确性,相对误差与 \(\log_{2}(N)\) 成正比增长,其中 \(N\) 是点中的变换大小。

对于 Cooley-Tukey 代码路径处理的大小,通过应用以下约束(从最通用到最专业的约束顺序列出,每个后续约束都提供额外性能改进的潜力)可以获得最有效的实现。

由于半精度浮点运算表示的范围有限,半精度变换可能不适用于所有类型的问题。请注意,FFT 结果的第一个元素是所有输入元素的总和,对于某些输入,它很可能溢出。

只要在运行之间保持以下内容不变:计划输入参数、cuFFT 版本和 GPU 型号,cuFFT 库生成的结果是确定性的(即,按位可重复)。

cuFFT 批处理计划要求输入数据包含所有批次的有效信号。批处理模式下的性能优化可以组合来自不同批次的信号进行处理。cuFFT 中使用的优化可能因版本而异。

适用于

建议

注释

全部

使用单精度变换。

单精度变换比双精度变换需要更少的每次计算带宽。

全部

将所有维度的大小限制为可表示为 \(2^{a} \times 3^{b} \times 5^{c} \times 7^{d}\)

cuFFT 库针对维度具有这些质因数的变换具有高度优化的内核。通常,最佳性能发生在 使用 2 的幂时,其次是 3 的幂,然后是 5、7。

全部

限制每个维度的大小以使用更少的不同质因数。

大小为 \(2^{n}\)\(3^{n}\) 的变换通常比大小为 \(2^{i} \times 3^{j}\) 的变换更快,即使后者略小,这是由于专门路径的组合。

全部

执行单个变换时,限制数据在内存中是连续的。执行多个变换时,使各个数据集连续

cuFFT 库已针对此数据布局进行了优化。

全部

执行多个(即,批处理)变换。

在批处理模式下执行额外的优化。

实数到复数变换或复数到实数变换

确保 x 维的问题大小是 4 的倍数。

此方案使用更高效的内核来实现共轭对称属性。

实数到复数变换或复数到实数变换

使用 out-of-place 模式。

此方案比 in-place 模式使用更高效的内核。

多 GPU 变换

在 GPU 之间使用 PCI Express 3.0,并确保 GPU 位于同一交换机上。

GPU 之间的互连速度越快,性能就越快。

2.14. 调用方分配的工作区支持

cuFFT 计划可能会使用额外的内存来存储中间结果。cuFFT 库提供多个函数来管理此临时内存利用率行为

  • cufftSetAutoAllocation

  • cufftEstimate1dcufftEstimate2dcufftEstimate3dcufftEstimateMany

  • cufftGetSize

  • cufftXtSetWorkAreaPolicy

前两个函数管理临时内存的分配和所有权。默认情况下,cuFFT 始终在 GPU 内存中分配自己的工作区。每个 cuFFT 句柄单独分配数据。如果要顺序启动多个 cuFFT 计划,可以将同一内存块分配为所有这些计划的工作区,并减少内存开销。

分配为工作区的内存需要对 GPU 可见。除了使用 cudaMalloc 获取的常规内存之外,CUDA 统一虚拟寻址的使用使 cuFFT 能够使用以下类型的内存作为工作区内存:pinned 主机内存、托管内存、GPU 上而不是执行计算的 GPU 上的内存。虽然这提供了灵活性,但它会带来性能损失,其大小取决于可用的内存带宽。

cufftEstimateNdcufftEstimateManycufftGetSize 函数提供有关用户分配工作区缓冲区的情况下所需内存大小的信息。

在版本 9.2 中,cuFFT 还引入了 cufftXtSetWorkAreaPolicy 函数。此函数允许微调工作区内存使用情况。
cuFFT 9.2 版本仅支持 CUFFT_WORKAREA_MINIMAL 策略,该策略指示 cuFFT 重新规划现有计划,而无需使用工作区内存。

同样从 cuFFT 9.2 开始,支持允许 CUFFT_WORKAREA_MINIMAL 策略的 FFT 变换如下

  • 任何维度中大小高达 4096 的 C2C 类型的变换均受支持。

  • 任何维度中大小高达 2048 的 Z2Z 类型的变换均受支持。

  • 仅支持单 GPU 变换。

根据 FFT 变换大小,设置 CUFFT_WORKAREA_MINIMAL 策略时,可能会使用不同的 FFT 算法。

3. cuFFT API 参考

本章通过描述 cuFFT 库函数的输入/输出参数、数据类型和错误代码来指定其行为。cuFFT 库在首次调用 API 函数时初始化,并在销毁所有用户创建的 FFT 计划后自动关闭。

3.1. 返回值 cufftResult

CUFFT_SUCCESS 之外的所有 cuFFT 库返回值都指示当前 API 调用失败,用户应重新配置以纠正问题。可能的返回值定义如下

typedef enum cufftResult_t {
    CUFFT_SUCCESS        = 0,  //  The cuFFT operation was successful
    CUFFT_INVALID_PLAN   = 1,  //  cuFFT was passed an invalid plan handle
    CUFFT_ALLOC_FAILED   = 2,  //  cuFFT failed to allocate GPU or CPU memory
    CUFFT_INVALID_TYPE   = 3,  //  No longer used
    CUFFT_INVALID_VALUE  = 4,  //  User specified an invalid pointer or parameter
    CUFFT_INTERNAL_ERROR = 5,  //  Driver or internal cuFFT library error
    CUFFT_EXEC_FAILED    = 6,  //  Failed to execute an FFT on the GPU
    CUFFT_SETUP_FAILED   = 7,  //  The cuFFT library failed to initialize
    CUFFT_INVALID_SIZE   = 8,  //  User specified an invalid transform size
    CUFFT_UNALIGNED_DATA = 9,  //  No longer used
    CUFFT_INCOMPLETE_PARAMETER_LIST = 10, //  Missing parameters in call
    CUFFT_INVALID_DEVICE = 11, //  Execution of a plan was on different GPU than plan creation
    CUFFT_PARSE_ERROR    = 12, //  Internal plan database error
    CUFFT_NO_WORKSPACE   = 13  //  No workspace has been provided prior to plan execution
    CUFFT_NOT_IMPLEMENTED = 14, // Function does not implement functionality for parameters given.
    CUFFT_LICENSE_ERROR  = 15, // Used in previous versions.
    CUFFT_NOT_SUPPORTED  = 16  // Operation is not supported for parameters given.
} cufftResult;

鼓励用户检查 cuFFT 函数的返回值是否存在错误,如 cuFFT 代码示例 所示。

3.2. cuFFT 基本计划

这些 API 例程负责初始化 cufftHandle。传递给计划函数的任何已初始化的句柄属性都将被忽略。

3.2.1. cufftPlan1d()

cufftResult cufftPlan1d(cufftHandle *plan, int nx, cufftType type, int batch);

为指定的信号大小和数据类型创建 1D FFT 计划配置。batch 输入参数告诉 cuFFT 要配置多少个 1D 变换。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

参数
  • plan[In] – 指向未初始化的 cufftHandle 对象的指针。

  • nx[In] – 变换大小(例如,对于 256 点 FFT,为 256)。

  • type[In] – 变换数据类型(例如,单精度复数到复数的 CUFFT_C2C)。

  • batch[In] – 大小为 nx 的变换数量。请考虑对多个变换使用 cufftPlanMany

  • plan[Out] – 包含 cuFFT 1D 计划句柄值。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划锁定时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxbatch 参数不是支持的大小。

3.2.2. cufftPlan2d()

cufftResult cufftPlan2d(cufftHandle *plan, int nx, int ny, cufftType type);

根据指定的信号大小和数据类型创建 2D FFT 计划配置。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

参数
  • plan[In] – 指向未初始化的 cufftHandle 对象的指针。

  • nx[In]x 维度的变换大小。这是变换的最慢变化维度(在内存中跨步)。

  • ny[In]y 维度的变换大小。这是变换的最快变化维度(在内存中是连续的)。

  • type[In] – 变换数据类型(例如,单精度复数到实数的 CUFFT_C2R)。

  • plan[Out] – 包含 cuFFT 2D 计划句柄值。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划锁定时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxny 参数之一或两者都不是支持的大小。

3.2.3. cufftPlan3d()

cufftResult cufftPlan3d(cufftHandle *plan, int nx, int ny, int nz, cufftType type);

根据指定的信号大小和数据类型创建 3D FFT 计划配置。此函数与 cufftPlan2d() 相同,不同之处在于它接受第三个大小参数 nz

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

参数
  • plan[In] – 指向未初始化的 cufftHandle 对象的指针。

  • nx[In]x 维度的变换大小。这是变换的最慢变化维度(在内存中跨步)。

  • ny[In]y 维度的变换大小。

  • nz[In]z 维度的变换大小。这是变换的最快变化维度(在内存中连续)。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • plan[Out] – 包含 cuFFT 3D 计划句柄值。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划锁定时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxnynz 参数中的一个或多个不是支持的大小。

3.2.4. cufftPlanMany()

cufftResult cufftPlanMany(cufftHandle *plan, int rank, int *n, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, cufftType type, int batch);

创建维度为 rank 的 FFT 计划配置,大小在数组 n 中指定。batch 输入参数告诉 cuFFT 要配置多少个变换。使用此函数,可以创建 1、2 或 3 维的批处理计划。

cufftPlanMany() API 通过高级数据布局参数支持更复杂的输入和输出数据布局:inembedistrideidistonembedostrideodist

如果 inembedonembed 设置为 NULL,则所有其他步幅信息将被忽略,并使用默认步幅。默认值假定为连续数据数组。

所有数组都假定在 CPU 内存中。

请注意,当 inembedonembedNULL 时,cufftPlanMany 函数的行为与 FFTW 库 fftw_plan_many_dft 中的对应函数不同。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

参数
  • plan[In] – 指向未初始化的 cufftHandle 对象的指针。

  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小,n[0] 是最外层维度的大小,而 n[rank-1] 是变换的最内层(连续)维度。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • batch[In] – 此变换的批次大小。

  • plan[Out] – 包含 cuFFT 计划句柄。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划锁定时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.3. cuFFT 可扩展计划

这些 API 例程将句柄创建与计划生成分离。这使得在实际生成计划之前,可以更改计划设置,这可能会改变计划生成阶段的结果。

3.3.1. cufftCreate()

cufftResult cufftCreate(cufftHandle *plan)

仅创建不透明句柄,并在主机上分配小型数据结构。cufftMakePlan*() 调用实际执行计划生成。

参数
  • plan[In] – 指向 cufftHandle 对象的指针。

  • plan[Out] – 包含 cuFFT 计划句柄值。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_ALLOC_FAILED – 计划的资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.3.2. cufftDestroy()

cufftResult cufftDestroy(cufftHandle plan)

释放与 cuFFT 计划关联的所有 GPU 资源,并销毁内部计划数据结构。一旦不再需要计划,就应调用此函数,以避免浪费 GPU 内存。对于多 GPU 计划,应最后销毁首先创建的计划。

参数
  • plan[In] – 要销毁的计划的 cufftHandle 对象。

返回值
  • CUFFT_SUCCESS – cuFFT 成功销毁了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

3.3.3. cufftMakePlan1d()

cufftResult cufftMakePlan1d(cufftHandle plan, int nx, cufftType type, int batch, size_t *workSize);

在调用 cufftCreate() 之后,为指定的信号大小和数据类型创建 1D FFT 计划配置。batch 输入参数告诉 cuFFT 要配置多少个 1D 变换。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

如果在调用此函数之前调用了 cufftXtSetGPUs() 且使用了多个 GPU,则 workSize 将包含多个大小。有关更多详细信息,请参阅关于多 GPU 的章节。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nx[In] – 变换大小(例如,对于 256 点 FFT,为 256)。对于多个 GPU,这必须是 2 的幂。

  • type[In] – 变换数据类型(例如,单精度复数到复数的 CUFFT_C2C)。对于多个 GPU,这必须是复数到复数的变换。

  • batch[In] – 大小为 nx 的变换数量。请考虑使用 cufftMakePlanMany 进行多次变换。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划被锁定或不满足多 GPU 限制时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED` – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxbatch 参数不是支持的大小。

3.3.4. cufftMakePlan2d()

cufftResult cufftMakePlan2d(cufftHandle plan, int nx, int ny, cufftType type, size_t *workSize);

在调用 cufftCreate() 之后,根据指定的信号大小和数据类型创建 2D FFT 计划配置。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

如果在调用此函数之前调用了 cufftXtSetGPUs() 且使用了多个 GPU,则 workSize 将包含多个大小。有关更多详细信息,请参阅关于多 GPU 的章节。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nx[In]x 维度的变换大小。这是变换的最慢变化维度(在内存中跨步)。对于多个 GPU,这必须可以分解为小于或等于 127 的素数。

  • ny[In]y 维度的变换大小。这是变换的最快变化维度(在内存中连续)。对于 2 个 GPU,这必须可以分解为小于或等于 127 的素数。

  • type[In] – 变换数据类型(例如,单精度复数到实数的 CUFFT_C2R)。

  • workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxny 参数之一或两者都不是支持的大小。

3.3.5. cufftMakePlan3d()

cufftResult cufftMakePlan3d(cufftHandle plan, int nx, int ny, int nz, cufftType type, size_t *workSize);

在调用 cufftCreate() 之后,根据指定的信号大小和数据类型创建 3D FFT 计划配置。此函数与 cufftPlan2d() 相同,不同之处在于它接受第三个大小参数 nz

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

如果在调用此函数之前调用了 cufftXtSetGPUs() 且使用了多个 GPU,则 workSize 将包含多个大小。有关更多详细信息,请参阅关于多 GPU 的章节。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nx[In]x 维度的变换大小。这是变换的最慢变化维度(在内存中跨步)。对于多个 GPU,这必须可以分解为小于或等于 127 的素数。

  • ny[In]y 维度的变换大小。对于多个 GPU,这必须可以分解为小于或等于 127 的素数。

  • nz[In]z 维度的变换大小。这是变换的最快变化维度(在内存中连续)。对于多个 GPU,这必须可以分解为小于或等于 127 的素数。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxnynz 参数中的一个或多个不是支持的大小。

3.3.6. cufftMakePlanMany()

cufftResult cufftMakePlanMany(cufftHandle plan, int rank, int *n, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, cufftType type, int batch, size_t *workSize);

在调用 cufftCreate() 之后,创建维度为 rank 的 FFT 计划配置,大小在数组 n 中指定。batch 输入参数告诉 cuFFT 要配置多少个变换。使用此函数,可以创建 1、2 或 3 维的批处理计划。

cufftPlanMany() API 通过高级数据布局参数支持更复杂的输入和输出数据布局:inembedistrideidistonembedostrideodist

如果 inembedonembed 设置为 NULL,则所有其他步幅信息将被忽略,并使用默认步幅。默认值假定为连续数据数组。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

如果在调用此函数之前调用了 cufftXtSetGPUs() 且使用了多个 GPU,则 workSize 将包含多个大小。有关更多详细信息,请参阅关于多 GPU 的章节。

所有数组都假定在 CPU 内存中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • rank[In] – 变换的维度(1、2 或 3)

  • n[In] – 大小为 rank 的数组,描述每个维度的大小,n[0] 是最外层维度的大小,而 n[rank-1] 是变换的最内层(连续)维度。对于多个 GPU 且 rank 等于 1,大小必须是 2 的幂。对于多个 GPU 且 rank 等于 2 或 3,大小必须可以分解为小于或等于 127 的素数。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度,inembed[0] 是最外层维度的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度,onembed[0] 是最外层维度的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。对于 2 个 GPU,这必须是复数到复数的变换。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划被锁定或不满足多 GPU 限制时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.3.7. cufftMakePlanMany64()

cufftResult cufftMakePlanMany64(cufftHandle plan, int rank, long long int *n, long long int *inembed, long long int istride, long long int idist, long long int *onembed, long long int ostride, long long int odist, cufftType type, long long int batch, size_t *workSize);

在调用 cufftCreate() 之后,创建维度为 rank 的 FFT 计划配置,大小在数组 n 中指定。batch 输入参数告诉 cuFFT 要配置多少个变换。使用此函数,可以创建 1、2 或 3 维的批处理计划。

此 API 与 cufftMakePlanMany 相同,不同之处在于指定大小和步幅的参数是 64 位整数。此 API 使非常大的变换成为可能。cuFFT 包括使用 32 位索引的内核和使用 64 位索引的内核。cuFFT 计划在可能的情况下选择 32 位内核,以避免因 64 位算术运算而产生的任何开销。

此接口支持所有大小和类型的变换,但有两个例外。对于大小超过 4G 元素的变换,数组 n 中指定的维度必须可以分解为小于或等于 127 的素数。对于大小超过 4G 元素的实数到复数和复数到实数变换,最快变化的维度必须是偶数。

cufftPlanMany64() API 通过高级数据布局参数支持更复杂的输入和输出数据布局:inembedistrideidistonembedostrideodist

如果 inembedonembed 设置为 NULL,则所有其他步幅信息将被忽略,并使用默认步幅。默认值假定为连续数据数组。

此调用对于给定的句柄只能使用一次。如果计划已锁定,即句柄先前已与不同的 cufftPlancufftMakePlan 调用一起使用,则此调用将失败并返回 CUFFT_INVALID_PLAN

如果在调用此函数之前调用了 cufftXtSetGPUs() 且使用了多个 GPU,则 workSize 将包含多个大小。有关更多详细信息,请参阅关于多 GPU 的章节。

所有数组都假定在 CPU 内存中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小。对于多个 GPU 且 rank 等于 1,大小必须是 2 的幂。对于多个 GPU 且 rank 等于 2 或 3,大小必须可以分解为小于或等于 127 的素数。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。对于 2 个 GPU,这必须是复数到复数的变换。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当计划被锁定或不满足多 GPU 限制时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.3.8. cufftXtMakePlanMany()

cufftResult cufftXtMakePlanMany(cufftHandle plan, int rank, long long int *n, long long int *inembed, long long int istride, long long int idist, cudaDataType inputtype, long long int *onembed, long long int ostride, long long int odist, cudaDataType outputtype, long long int batch, size_t *workSize, cudaDataType executiontype);

在调用 cufftCreate() 之后,创建维度为 rank 的 FFT 计划配置,大小在数组 n 中指定。batch 输入参数告诉 cuFFT 要配置多少个变换。使用此函数,可以创建 1、2 或 3 维的批处理计划。

类型说明符 inputtypeoutputtypeexecutiontype 指示要执行的变换的类型和精度。并非所有参数组合都受支持。目前,所有三个参数都需要匹配精度。inputtypeoutputtype 参数需要匹配变换类型:复数到复数、实数到复数或复数到实数。executiontype 参数需要匹配精度并且必须是复数类型。示例:对于半精度实数到复数变换,参数 inputtypeoutputtypeexecutiontype 的值将分别为 CUDA_R_16FCUDA_C_16FCUDA_C_16F。类似地,bfloat16 复数到实数变换将对 inputtypeexecutiontype 使用 CUDA_C_16BF,对 outputtype 使用 CUDA_R_16BF

cufftXtMakePlanMany() API 通过高级数据布局参数支持更复杂的输入和输出数据布局:inembedistrideidistonembedostrideodist

如果 inembedonembed 设置为 NULL,则所有其他步幅信息将被忽略,并使用默认步幅。默认值假定为连续数据数组。

如果在调用此函数之前调用了 cufftXtSetGPUs() 且使用了多个 GPU,则 workSize 将包含多个大小。有关更多详细信息,请参阅关于多 GPU 的章节。

所有数组都假定在 CPU 内存中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小,n[0] 是最外层维度的大小,而 n[rank-1] 是变换的最内层(连续)维度。对于多个 GPU 且 rank 等于 1,大小必须是 2 的幂。对于多个 GPU 且 rank 等于 2 或 3,大小必须可以分解为小于或等于 127 的素数。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度,inembed[0] 是最外层维度的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • inputtype[In] – 输入数据的类型。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度,onembed[0] 是最外层维度的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • outputtype[In] – 输出数据的类型。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • executiontype[In] – 用于计算的数据类型。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功创建了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。当不满足多 GPU 限制时,句柄无效。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.4. cuFFT 计划属性

用户可以使用计划属性进一步自定义 cuFFT 计划。可以使用本节中列出的例程根据需要为每个计划设置、查询和重置这些属性。

当前支持的属性如下所示

属性

底层类型

描述

行为

NVFFT_PLAN_PROPERTY_INT64_PATIENT_JIT

long long int

  • 当设置为非零值时,运行时 LTO 内核已启用。请参阅链接时优化内核

  • 当设置为零(默认值)时,运行时 LTO 内核已禁用

  • 可以在计划之前设置/重置

  • 无法在计划之后设置/重置

3.4.1. cufftSetPlanPropertyInt64()

cufftResult cufftSetPlanPropertyInt64(cufftHandle plan, cufftProperty property, const long long int propertyValueInt64);

将 cuFFT 计划与由键 property 标识的属性关联。属性的值由值 propertyValueInt64 给出,这是一个有符号的 long long 整数。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • property[In] – 属性标识符,类型为 cufftPlanProperty

  • propertyValueInt64[In] – 要为属性设置的值,一个 long long 有符号整数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功设置了属性。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_NOT_SUPPORTED – 不支持该属性,或者此时无法设置该属性(例如,某些属性在调用计划的计划例程后无法设置,请参阅cuFFT 计划属性)。

  • CUFFT_INVALID_VALUE – 属性无效或用于设置属性的值无效

3.4.2. cufftGetPlanPropertyInt64()

cufftResult cufftGetPlanPropertyInt64(cufftHandle plan, cufftProperty property, long long int *propertyValueInt64);

检索与 cuFFT 计划 plan 关联的、由键 property 标识的属性值。属性值(有符号长长整型)将被设置在 propertyValueInt64 指向的地址空间中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • property[In] – 属性标识符,类型为 cufftPlanProperty

  • propertyValueInt64[In] – 指向要使用属性值设置的值的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功检索到属性值。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_NOT_SUPPORTED – 不支持该属性。

  • CUFFT_INVALID_VALUE – 属性无效,或指针 propertyValueInt64 为空。

3.4.3. cufftResetPlanProperty()

cufftResult cufftResetPlanProperty(cufftHandle plan, cufftProperty property);

将与 cuFFT 计划 plan 关联的、由键 property 标识的属性值重置为其默认值。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • property[In] – 属性标识符,类型为 cufftPlanProperty

返回值
  • CUFFT_SUCCESS – cuFFT 成功重置了属性值。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_NOT_SUPPORTEDplan 不支持该属性,或者目前无法重置(请参阅 cuFFT 计划属性上的“行为”列)。

  • CUFFT_INVALID_VALUE – 属性无效。

3.5. cuFFT 工作区大小估计

在计划执行期间,cuFFT 需要一个工作区来临时存储中间结果。cufftEstimate*() 调用返回给定指定参数并假设默认计划设置所需工作区大小的估计值。一些问题规模比其他问题规模需要更多的存储空间。特别是 2 的幂在临时存储方面非常高效。然而,较大的素数使用不同的算法,可能需要高达相似大小的 2 的幂的八倍。这些例程返回估计的 workSize 值,这些值可能仍然小于实际需要的值,特别是对于不是 2、3、5 和 7 的幂的倍数的 n 值。更精确的值由 cufftGetSize*() 例程给出,但这些值可能仍然是保守的。

3.5.1. cufftEstimate1d()

cufftResult cufftEstimate1d(int nx, cufftType type, int batch, size_t *workSize);

在计划执行期间,cuFFT 需要一个工作区来临时存储中间结果。此调用返回给定指定参数并假设默认计划设置所需工作区大小的估计值。

参数
  • nx[In] – 变换大小(例如,对于 256 点 FFT,为 256)。

  • type[In] – 变换数据类型(例如,单精度复数到复数的 CUFFT_C2C)。

  • batch[In] – 大小为 nx 的变换数量。请考虑对多个变换使用 cufftEstimateMany

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnx 参数不是支持的大小。

3.5.2. cufftEstimate2d()

cufftResult cufftEstimate2d(int nx, int ny, cufftType type, size_t *workSize);

在计划执行期间,cuFFT 需要一个工作区来临时存储中间结果。此调用返回给定指定参数并假设默认计划设置所需工作区大小的估计值。

参数
  • nx[In]x 维度(行数)的变换大小。

  • ny[In]y 维度(列数)的变换大小。

  • type[In] – 变换数据类型(例如,单精度复数到实数的 CUFFT_C2R)。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxny 参数之一或两者都不是支持的大小。

3.5.3. cufftEstimate3d()

cufftResult cufftEstimate3d(int nx, int ny, int nz, cufftType type, size_t *workSize);

在计划执行期间,cuFFT 需要一个工作区来临时存储中间结果。此调用返回给定指定参数并假设默认计划设置所需工作区大小的估计值。

参数
  • nx[In]x 维度的变换大小。

  • ny[In]y 维度的变换大小。

  • nz[In]z 维度的变换大小。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxnynz 参数中的一个或多个不是支持的大小。

3.5.4. cufftEstimateMany()

cufftResult cufftEstimateMany(int rank, int *n, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, cufftType type, int batch, size_t *workSize);

在计划执行期间,cuFFT 需要一个工作区来临时存储中间结果。此调用返回给定指定参数并假设默认计划设置所需工作区大小的估计值。

cufftEstimateMany() API 通过高级数据布局参数:inembedistrideidistonembedostrideodist,支持更复杂的输入和输出数据布局。

所有数组都假定在 CPU 内存中。

参数
  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.6. cuFFT 精细估计的工作区大小

cufftGetSize*() 例程比 cufftEstimate*() 例程更准确地估计计划所需的工作区大小,因为它们考虑了可能已进行的任何计划设置。正如 cuFFT 工作区大小估计部分所讨论的,返回的 workSize 值可能仍然是保守的,特别是对于不是 2、3、5 和 7 的幂的倍数的 n 值。

3.6.1. cufftGetSize1d()

cufftResult cufftGetSize1d(cufftHandle plan, int nx, cufftType type, int batch, size_t *workSize);

此调用比 cufftEstimate1d() 更准确地估计计划所需的工作区大小,给定指定的参数,并考虑可能已进行的任何计划设置。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nx[In] – 变换大小(例如,对于 256 点 FFT,为 256)。

  • type[In] – 变换数据类型(例如,单精度复数到复数的 CUFFT_C2C)。

  • batch[In] – 大小为 nx 的变换数量。请考虑对多个变换使用 cufftGetSizeMany

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnx 参数不是支持的大小。

3.6.2. cufftGetSize2d()

cufftResult cufftGetSize2d(cufftHandle plan, int nx, int ny, cufftType type, size_t *workSize);

此调用比 cufftEstimate2d() 更准确地估计计划所需的工作区大小,给定指定的参数,并考虑可能已进行的任何计划设置。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nx[In]x 维度(行数)的变换大小。

  • ny[In]y 维度(列数)的变换大小。

  • type[In] – 变换数据类型(例如,单精度复数到实数的 CUFFT_C2R)。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxny 参数之一或两者都不是支持的大小。

3.6.3. cufftGetSize3d()

cufftResult cufftGetSize3d(cufftHandle plan, int nx, int ny, int nz, cufftType type, size_t *workSize);

此调用比 cufftEstimate3d() 更准确地估计计划所需的工作区大小,给定指定的参数,并考虑可能已进行的任何计划设置。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nx[In]x 维度的变换大小。

  • ny[In]y 维度的变换大小。

  • nz[In]z 维度的变换大小。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZEnxnynz 参数中的一个或多个不是支持的大小。

3.6.4. cufftGetSizeMany()

cufftResult cufftGetSizeMany(cufftHandle plan, int rank, int *n, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, cufftType type, int batch, size_t *workSize);

此调用比 cufftEstimateSizeMany() 更准确地估计计划所需的工作区大小,给定指定的参数,并考虑可能已进行的任何计划设置。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.6.5. cufftGetSizeMany64()

cufftResult cufftGetSizeMany64(cufftHandle plan, int rank, long long int *n, long long int *inembed, long long int istride, long long int idist, long long int *onembed, long long int ostride, long long int odist, cufftType type, long long int batch, size_t *workSize);

此调用比 cufftEstimateSizeMany() 更准确地估计计划所需的工作区大小,给定指定的参数,并考虑可能已进行的任何计划设置。

此 API 与 cufftMakePlanMany 相同,不同之处在于指定大小和步幅的参数是 64 位整数。此 API 使非常大的变换成为可能。cuFFT 包括使用 32 位索引的内核和使用 64 位索引的内核。cuFFT 计划在可能的情况下选择 32 位内核,以避免因 64 位算术运算而产生的任何开销。

此接口支持所有大小和类型的变换,但有两个例外。对于总大小超过 4G 元素的变换,数组 n 中指定的维度必须可分解为小于或等于 127 的素数。对于总大小超过 4G 元素的实数到复数和复数到实数变换,最快变化的维度必须是偶数。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • type[In] – 变换数据类型(例如,单精度实数到复数的 CUFFT_R2C)。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.6.6. cufftXtGetSizeMany()

cufftResult cufftXtGetSizeMany(cufftHandle plan, int rank, long long int *n, long long int *inembed, long long int istride, long long int idist, cudaDataType inputtype, long long int *onembed, long long int ostride, long long int odist, cudaDataType outputtype, long long int batch, size_t *workSize, cudaDataType executiontype);

此调用比 cufftEstimateSizeMany() 更准确地估计计划所需的工作区大小,给定与 cufftXtMakePlanMany 函数签名匹配的指定参数,并考虑可能已进行的任何计划设置。

有关 inputtypeoutputtypeexecutiontype 参数的有效组合的更多信息,请参阅 cufftXtMakePlanMany 函数的文档。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • rank[In] – 变换的维度(1、2 或 3)。

  • n[In] – 大小为 rank 的数组,描述每个维度的大小。

  • inembed[In] – 大小为 rank 的指针,指示输入数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • istride[In] – 指示最不重要(即最内层)维度中两个连续输入元素之间的距离。

  • idist[In] – 指示输入数据批次中两个连续信号的第一个元素之间的距离。

  • inputtype[In] (cudaDataType) – 输入数据类型。

  • onembed[In] – 大小为 rank 的指针,指示输出数据在内存中的存储维度。如果设置为 NULL,则所有其他高级数据布局参数都将被忽略。

  • ostride[In] – 指示输出数组中最不重要(即最内层)维度中两个连续输出元素之间的距离。

  • odist[In] – 指示输出数据批次中两个连续信号的第一个元素之间的距离。

  • outputtype[In] (cudaDataType) – 输出数据类型。

  • batch[In] – 此变换的批次大小。

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • executiontype[In] (cudaDataType) – 用于计算的数据类型。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_SIZE – 一个或多个参数不是支持的大小。

3.7. cufftGetSize()

cufftResult cufftGetSize(cufftHandle plan, size_t *workSize);

一旦完成计划生成(使用原始 API 或可扩展 API),此调用将返回支持该计划所需的工作区的实际大小。选择在其应用程序中管理工作区分配的调用者必须在计划生成之后以及在计划生成之后的任何 cufftSet*() 调用之后使用此调用,如果这些调用可能会更改所需的工作区大小。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • *workSize[In] – 指向工作区大小(以字节为单位)的指针。例如,对于两个 GPU,必须声明 worksize 具有两个元素。

  • *workSize[Out] – 指向工作区大小的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

3.8. cuFFT 调用方分配的工作区支持

3.8.1. cufftSetAutoAllocation()

cufftResult cufftSetAutoAllocation(cufftHandle plan, int autoAllocate);

cufftSetAutoAllocation() 指示调用方打算为已生成的计划分配和管理工作区。cuFFT 默认行为是在计划生成时分配工作区。如果在调用 cufftMakePlan*() 之一之前调用了 cufftSetAutoAllocation(),并将 autoAllocate 设置为 0(“false”),则 cuFFT 不会分配工作区。这是希望管理工作区分配的调用方的首选顺序。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • autoAllocate[In] – 指示是否分配工作区。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

3.8.2. cufftSetWorkArea()

cufftResult cufftSetWorkArea(cufftHandle plan, void *workArea);

cufftSetWorkArea() 覆盖与计划关联的工作区指针。如果工作区是自动分配的,则 cuFFT 会释放自动分配的空间。cufftExecute*() 调用假定工作区指针有效,并且它指向设备内存中的一个连续区域,该区域不与其他任何工作区重叠。如果情况并非如此,则结果是不确定的。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • *workArea[In] – 指向 workArea 的指针。对于多个 GPU,必须给出多个工作区指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.8.3. cufftXtSetWorkAreaPolicy()

cufftResult cufftXtSetWorkAreaPolicy(cufftHandle plan, cufftXtWorkAreaPolicy policy, size_t *workSize);

cufftXtSetWorkAreaPolicy() 指示调用方打算更改给定计划句柄的工作区大小。cuFFT 的默认行为是在计划生成时分配工作区,其默认大小取决于计划类型和其他参数。如果调用了 cufftXtSetWorkAreaPolicy(),并将 policy 参数设置为 CUFFT_WORKAREA_MINIMAL,则 cuFFT 将尝试重新计划句柄以使用零字节的工作区内存。如果 cufftXtSetWorkAreaPolicy() 调用成功,则会自动释放分配的工作区内存。

目前,策略 CUFFT_WORKAREA_PERFORMANCECUFFT_WORKAREA_USERworkSize 参数不受支持,并保留供未来 cuFFT 版本使用。

此函数在一个计划句柄的生命周期内可以调用一次。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • policy[In] – 要应用的工作区策略类型。

  • *workSize[In] – 保留供将来使用。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_SIZE – FFT 大小不允许使用选定的策略。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.9. cuFFT 执行

3.9.1. cufftExecC2C() 和 cufftExecZ2Z()

cufftResult cufftExecC2C(cufftHandle plan, cufftComplex *idata, cufftComplex *odata, int direction);
cufftResult cufftExecZ2Z(cufftHandle plan, cufftDoubleComplex *idata, cufftDoubleComplex *odata, int direction);

cufftExecC2C() (cufftExecZ2Z()) 执行单精度(双精度)复数到复数的变换计划,变换方向由 direction 参数指定。cuFFT 使用 idata 参数指向的 GPU 内存作为输入数据。此函数将傅里叶系数存储在 odata 数组中。如果 idataodata 相同,则此方法执行就地变换。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • idata[In] – 指向要变换的复数输入数据(在 GPU 内存中)的指针。

  • odata[In] – 指向复数输出数据(在 GPU 内存中)的指针。

  • direction[In] – 变换方向:CUFFT_FORWARDCUFFT_INVERSE

  • odata[Out] – 包含复数傅里叶系数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 idataodatadirection 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.9.2. cufftExecR2C() 和 cufftExecD2Z()

cufftResult cufftExecR2C(cufftHandle plan, cufftReal *idata, cufftComplex *odata);
cufftResult cufftExecD2Z(cufftHandle plan, cufftDoubleReal *idata, cufftDoubleComplex *odata);

cufftExecR2C() (cufftExecD2Z()) 执行单精度(双精度)实数到复数的、隐式正向的 cuFFT 变换计划。cuFFT 使用 idata 参数指向的 GPU 内存作为输入数据。此函数将非冗余的傅里叶系数存储在 odata 数组中。单精度变换中,指向 idataodata 的指针都必须对齐到 cufftComplex 数据类型,双精度变换中则必须对齐到 cufftDoubleComplex 数据类型。如果 idataodata 相同,则此方法执行就地变换。请注意就地变换和异地变换之间的数据布局差异,如参数 cufftType 中所述。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • idata[In] – 指向要变换的实数输入数据(在 GPU 内存中)的指针。

  • odata[In] – 指向复数输出数据(在 GPU 内存中)的指针。

  • odata[Out] – 包含复数傅里叶系数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功返回工作区的大小。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 idataodata 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.9.3. cufftExecC2R() 和 cufftExecZ2D()

cufftResult cufftExecC2R(cufftHandle plan, cufftComplex *idata, cufftReal *odata);
cufftResult cufftExecZ2D(cufftHandle plan, cufftDoubleComplex *idata, cufftDoubleReal *odata);

cufftExecC2R() (cufftExecZ2D()) 执行单精度(双精度)复数到实数的、隐式反向的 cuFFT 变换计划。cuFFT 使用 idata 参数指向的 GPU 内存作为输入数据。输入数组仅包含非冗余的复数傅里叶系数。此函数将实数输出值存储在 odata 数组中。单精度变换中,指针都必须对齐到 cufftComplex 数据类型,双精度变换中则必须对齐到 cufftDoubleComplex 类型。如果 idataodata 相同,则此方法执行就地变换。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • idata[In] – 指向要变换的复数输入数据(在 GPU 内存中)的指针。

  • odata[In] – 指向实数输出数据(在 GPU 内存中)的指针。

  • odata[Out] – 包含实数输出数据。

返回值
  • CUFFT_SUCCESS – cuFFT 成功执行了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 idataodata 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.9.4. cufftXtExec()

cufftResult cufftXtExec(cufftHandle plan, void *input, void *output, int direction);

函数 cufftXtExec 执行任何 cuFFT 变换,无论精度和类型如何。对于复数到实数和实数到复数的变换,direction 参数将被忽略。cuFFT 使用 input 参数指向的 GPU 内存作为输入数据。此函数将傅里叶系数存储在 output 数组中。如果 inputoutput 相同,则此方法执行就地变换。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • input[In] – 指向要变换的输入数据(在 GPU 内存中)的指针。

  • output[In] – 指向输出数据(在 GPU 内存中)的指针。

  • direction[In] – 变换方向:CUFFT_FORWARDCUFFT_INVERSE。对于复数到实数和实数到复数的变换将被忽略。

  • output[Out] – 包含复数傅里叶系数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功执行了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 idataodatadirection 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.9.5. cufftXtExecDescriptor()

cufftResult cufftXtExecDescriptor(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output, int direction);

函数 cufftXtExecDescriptor() 执行任何 cuFFT 变换,无论精度和类型如何。对于复数到实数和实数到复数的变换,direction 参数将被忽略。cuFFT 使用 cudaLibXtDesc                                         *input 描述符指向的 GPU 内存作为输入数据,并使用 cudaLibXtDesc *output 作为输出数据。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • input[In] – 指向要变换的复数输入数据(在 GPU 内存中)的指针。

  • output[In] – 指向复数输出数据(在 GPU 内存中)的指针。

  • direction[In] – 变换方向:CUFFT_FORWARDCUFFT_INVERSE。对于复数到实数和实数到复数的变换将被忽略。

  • idata[Out] – 包含复数傅里叶系数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功执行了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 idatadirection 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 在描述符中指定了无效的 GPU 索引。

3.10. cuFFT 和多 GPU

3.10.1. cufftXtSetGPUs()

cufftResult cufftXtSetGPUs(cufftHandle plan, int nGPUs, int *whichGPUs);

cufftXtSetGPUs() 标识计划要使用的 GPU。与单 GPU 情况一样,cufftCreate() 创建计划,cufftMakePlan*() 执行计划生成。在 10.4.0 之前的 cuFFT 版本中,如果计划已关联非默认流,则此调用将返回错误。

请注意,对 cufftXtSetGPUs() 的调用必须发生在对 cufftCreate() 的调用之后,且在对 cufftMakePlan*() 的调用之前。cufftXtSetGPUs() 函数的参数 whichGPUs 确定 GPU 相对于数据分解的顺序(第一个数据块放置在 whichGPUs 的第一个元素表示的 GPU 上)。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • nGPUs[In] – 要使用的 GPU 数量。

  • whichGPUs[In] – 要使用的 GPU。

返回值
  • CUFFT_SUCCESS – cuFFT 成功设置了要使用的 GPU。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄,或者在 10.4.0 之前的 cuFFT 版本中,非默认流已与该计划关联

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_VALUE – 请求的 GPU 数量少于 2 个或多于 8 个。

  • CUFFT_INVALID_DEVICE – 指定了无效的 GPU 索引。

  • CUFFT_INVALID_SIZE – 为 plan 创建的变换大小不满足最小大小标准。

3.10.2. cufftXtSetWorkArea()

cufftResult cufftXtSetWorkArea(cufftHandle plan, void **workArea);

cufftXtSetWorkArea() 覆盖与计划关联的工作区。如果工作区是自动分配的,则 cuFFT 释放自动分配的空间。cufftXtExec*() 调用假定工作区有效,并且它指向每个设备内存中的连续区域,且不与其他任何工作区重叠。如果不是这种情况,则结果是不确定的。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • workArea[In] – 指向工作区指针的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功设置了要使用的 GPU。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 无法选择与计划关联的 GPU。

3.10.3. cuFFT 多 GPU 执行

3.10.3.1. cufftXtExecDescriptorC2C() 和 cufftXtExecDescriptorZ2Z()

cufftResult cufftXtExecDescriptorC2C(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output, int direction);
cufftResult cufftXtExecDescriptorZ2Z(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output, int direction);

cufftXtExecDescriptorC2C() (cufftXtExecDescriptorZ2Z()) 执行单精度(双精度)复数到复数的变换计划,变换方向由 direction 参数指定。cuFFT 使用 cudaLibXtDesc *input 指向的 GPU 内存作为输入数据。由于仅支持就地多 GPU 功能,因此此函数还将结果存储在 cudaLibXtDesc *input 数组中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • *input[In] – 指向要变换的复数输入数据(在 GPU 内存中)的指针。

  • *output[In] – 指向复数输出数据(在 GPU 内存中)的指针。

  • direction[In] – 变换方向:CUFFT_FORWARDCUFFT_INVERSE

  • input[Out] – 包含复数傅里叶系数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功执行了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 inputdirection 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 在描述符中指定了无效的 GPU 索引。

3.10.3.2. cufftXtExecDescriptorR2C() 和 cufftXtExecDescriptorD2Z()

cufftResult cufftXtExecDescriptorR2C(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output);
cufftResult cufftXtExecDescriptorD2Z(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output);

cufftXtExecDescriptorR2C() (cufftXtExecDescriptorD2Z()) 执行单精度(双精度)实数到复数的变换计划。cuFFT 使用 cudaLibXtDesc *input 指向的 GPU 内存作为输入数据。由于仅支持就地多 GPU 功能,因此此函数还将结果存储在 cudaLibXtDesc *input 数组中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • *input[In] – 指向要变换的复数输入数据(在 GPU 内存中)的指针。

  • *output[In] – 指向复数输出数据(在 GPU 内存中)的指针。

  • input[Out] – 包含复数傅里叶系数

返回值
  • CUFFT_SUCCESS – cuFFT 成功执行了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 inputdirection 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 在描述符中指定了无效的 GPU 索引。

3.10.3.3. cufftXtExecDescriptorC2R() 和 cufftXtExecDescriptorZ2D()

cufftResult cufftXtExecDescriptorC2R(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output);
cufftResult cufftXtExecDescriptorZ2D(cufftHandle plan, cudaLibXtDesc *input, cudaLibXtDesc *output);

cufftXtExecDescriptorC2R() (cufftXtExecDescriptorZ2D()) 执行单精度(双精度)复数到实数的变换计划,变换方向由 direction 参数指定。cuFFT 使用 cudaLibXtDesc *input 指向的 GPU 内存作为输入数据。由于仅支持就地多 GPU 功能,因此此函数还将结果存储在 cudaLibXtDesc *input 数组中。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • *input[In] – 指向要变换的复数输入数据(在 GPU 内存中)的指针。

  • *output[In] – 指向复数输出数据(在 GPU 内存中)的指针。

  • input[Out] – 包含复数傅里叶系数。

返回值
  • CUFFT_SUCCESS – cuFFT 成功执行了 FFT 计划。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 至少参数 inputdirection 之一无效。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_EXEC_FAILED – cuFFT 无法在 GPU 上执行变换。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 在描述符中指定了无效的 GPU 索引。

3.10.4. 内存分配和数据移动函数

多 GPU cuFFT 执行函数假定特定的数据布局,即在执行之前哪些输入数据已复制到哪些 GPU,以及执行后哪些输出数据驻留在哪些 GPU 中。以下函数有助于数据的分配、设置和检索。它们必须在调用 cufftMakePlan*() 之后调用。

3.10.4.1. cufftXtMalloc()

cufftResult cufftXtMalloc(cufftHandle plan, cudaLibXtDesc **descriptor, cufftXtSubFormat format);

cufftXtMalloc() 分配描述符,以及与计划关联的 GPU 中所有数据的内存,并返回指向描述符的指针。请注意,描述符包含设备指针数组,以便应用程序可以在 GPU 上预处理或后处理数据。枚举参数 cufftXtSubFormat_t 指示缓冲区将用于输入还是输出。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • **descriptor[In] – 指向 cudaLibXtDesc 对象指针的指针。

  • format[In] – cufftXtSubFormat`` 值。

  • **descriptor[Out] – 指向 cudaLibXtDesc 对象指针的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功允许用户分配描述符和 GPU 内存。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄,或者它不是多 GPU plan

  • CUFFT_ALLOC_FAILED – 计划的 GPU 资源分配失败。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 在描述符中指定了无效的 GPU 索引。

3.10.4.1.1. 参数 cufftXtSubFormat

cufftXtSubFormat_t 是一种枚举类型,指示缓冲区将用于输入还是输出以及数据的顺序。

typedef enum cufftXtSubFormat_t {
    CUFFT_XT_FORMAT_INPUT,              //by default input is in linear order across GPUs
    CUFFT_XT_FORMAT_OUTPUT,             //by default output is in scrambled order depending on transform
    CUFFT_XT_FORMAT_INPLACE,            //by default inplace is input order, which is linear across GPUs
    CUFFT_XT_FORMAT_INPLACE_SHUFFLED,   //shuffled output order after execution of the transform
    CUFFT_FORMAT_UNDEFINED
} cufftXtSubFormat;

3.10.4.2. cufftXtFree()

cufftResult cufftXtFree(cudaLibXtDesc *descriptor);

cufftXtFree() 释放描述符和与其关联的所有内存。描述符和内存必须由先前对 cufftXtMalloc() 的调用返回。

参数
  • *descriptor[In] – 指向 cudaLibXtDesc 对象的指针。

返回值
  • CUFFT_SUCCESS – cuFFT 成功允许用户释放描述符和关联的 GPU 内存。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

3.10.4.3. cufftXtMemcpy()

cufftResult cufftXtMemcpy(cufftHandle plan, void *dstPointer, void *srcPointer, cufftXtCopyType type);

cufftXtMemcpy() 在主机和 GPU 上的缓冲区之间或 GPU 之间复制数据。枚举参数 cufftXtCopyType_t 指示传输的类型和方向。不支持为传输类型为 CUFFT_COPY_DEVICE_TO_DEVICE 的多 GPU 批量 FFT 计划调用 cufftXtMemcpy 函数。

请注意,从 CUDA 11.2 (cuFFT 10.4.0) 开始,多 GPU 计划支持 cufftSetStream()。当将流与计划关联时,cufftXtMemcpy() 在多个 GPU 之间保持同步。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • dstPointer[In] – 指向目标地址的指针。

  • srcPointer[In] – 指向源地址的指针。

  • type[In]cufftXtCopyType 值。

返回值
  • CUFFT_SUCCESS – cuFFT 成功允许用户在主机和 GPU 之间或 GPU 之间复制内存。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄。

  • CUFFT_INVALID_VALUE – 向 API 传递了一个或多个无效参数。

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

  • CUFFT_INVALID_DEVICE – 在描述符中指定了无效的 GPU 索引。

3.10.4.3.1. 参数 cufftXtCopyType

cufftXtCopyType_t 是多 GPU 函数的枚举类型,用于指定 cufftXtMemcpy() 的复制类型。

CUFFT_COPY_HOST_TO_DEVICE 将数据从连续的主机缓冲区复制到多个设备缓冲区,采用 cuFFT 输入数据所需的布局。dstPointer 必须指向 cudaLibXtDesc 结构,srcPointer 必须指向主机内存缓冲区。

CUFFT_COPY_DEVICE_TO_HOST 将数据从多个设备缓冲区(采用 cuFFT 为输出数据生成的布局)复制到连续的主机缓冲区。dstPointer 必须指向主机内存缓冲区,srcPointer 必须指向 cudaLibXtDesc 结构。

CUFFT_COPY_DEVICE_TO_DEVICE 将数据从多个设备缓冲区(采用 cuFFT 为输出数据生成的布局)复制到多个设备缓冲区(采用 cuFFT 输入数据所需的布局)。dstPointersrcPointer 必须指向不同的 cudaLibXtDesc 结构(以及因此不同的内存位置)。也就是说,复制不能是就地的。请注意,当前不支持 2D 和 3D 数据的 device_to_device cufftXtMemcpy()

typedef enum cufftXtCopyType_t {
    CUFFT_COPY_HOST_TO_DEVICE,
    CUFFT_COPY_DEVICE_TO_HOST,
    CUFFT_COPY_DEVICE_TO_DEVICE
} cufftXtCopyType;

3.10.5. 通用多 GPU 描述符类型

3.10.5.1. cudaXtDesc

多 GPU 例程中使用的描述符类型,包含有关 GPU 及其内存位置的信息。

    struct cudaXtDesc_t{
    int version;                             //descriptor version
    int nGPUs;                               //number of GPUs
    int GPUs[MAX_CUDA_DESCRIPTOR_GPUS];      //array of device IDs
    void *data[MAX_CUDA_DESCRIPTOR_GPUS];    //array of pointers to data, one per GPU
    size_t size[MAX_CUDA_DESCRIPTOR_GPUS];   //array of data sizes, one per GPU
    void *cudaXtState;                       //opaque CUDA utility structure
};
typedef struct cudaXtDesc_t cudaXtDesc;

3.10.5.2. cudaLibXtDesc

在多个 GPU 例程中使用的描述符类型,包含有关所用库的信息。

struct cudaLibXtDesc_t{
    int version;                //descriptor version
    cudaXtDesc *descriptor;     //multi-GPU memory descriptor
    libFormat library;          //which library recognizes the format
    int subFormat;              //library specific enumerator of sub formats
    void *libDescriptor;        //library specific descriptor e.g. FFT transform plan object
};
typedef struct cudaLibXtDesc_t cudaLibXtDesc;

3.11. cuFFT 回调

3.11.1. cufftXtSetJITCallback()

cufftResult cufftXtSetJITCallback(cufftHandle plan, const char *callbackSymbolName, const void *callbackFatbin, size_t callbackFatbinSize, cufftXtCallbackType type, void **caller_info)

cufftXtSetJITCallback() 指定要与 plan 一起使用的加载或存储 LTO 回调。

此调用仅在调用 cufftCreate() 之后,但在调用执行 plan 生成的 cufftMakePlan*() 之前有效。

如果 plan 已经关联了此类型的 LTO 回调,则此新的回调例程将替换它。如果新的回调需要共享内存,则必须使用回调函数所需的共享内存量调用 cufftXtSetCallbackSharedSize。如果回调函数已更改,则 cuFFT 不会保留与先前回调关联的共享内存量。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • callbackSymbolName[In] – 包含(未损坏的)回调符号名称(即 LTO 回调例程的名称)的 null 终止 C 字符串。此符号名称将在运行时编译,并且不支持 extern "C"namespace 等修饰符。

  • callbackFatbin[In] – 指向主机内存中回调设备函数位置的指针,该函数在使用 nvcc 或 NVRTC 编译为 LTO-IR 后位于此处。

  • callbackFatbinSize[In]callbackFatbin 指向的数据的大小(以字节为单位)。

  • type[In] – 回调例程的类型。

  • callerInfo[In] – 可选的调用方特定信息设备指针数组,每个 GPU 一个。

返回值
  • CUFFT_SUCCESS – cuFFT 已成功将回调函数与 plan 关联。

  • CUFFT_INVALID_PLANplan 参数无效(例如,句柄已用于创建 plan)。

  • CUFFT_INVALID_TYPE – 回调类型无效。

  • CUFFT_INVALID_VALUE – 指向回调设备函数的指针无效或大小为 0

  • CUFFT_NOT_SUPPORTED – 尚不支持该功能(例如,具有 LTO 回调的多 GPU)。

  • CUFFT_INTERNAL_ERROR – cuFFT 遇到意外错误,可能在运行时链接过程中;错误代码将在未来的版本中扩展。

  • CUFFT_SETUP_FAILED – cuFFT 库初始化失败。

3.11.2. cufftXtSetCallback()

cufftResult cufftXtSetCallback(cufftHandle plan, void **callbackRoutine, cufftXtCallbackType type, void **callerInfo)

cufftXtSetCallback() 指定要与 plan 一起使用的加载或存储旧式回调。此调用仅在调用执行 plan 生成的 cufftMakePlan*() 之后有效。如果 plan 已经关联了此类型的旧式回调,则此新的回调例程将替换它。如果新的回调需要共享内存,则必须使用它所需的共享内存量调用 cufftXtSetCallbackSharedSize。cuFFT 不会保留与先前回调关联的共享内存量。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • callbackRoutine[In] – 回调例程指针数组,每个 GPU 一个。

  • type[In] – 回调例程的类型。

  • callerInfo[In] – 可选的调用方特定信息设备指针数组,每个 GPU 一个。

返回值

3.11.3. cufftXtClearCallback()

cufftResult cufftXtClearCallback(cufftHandle plan, cufftXtCallbackType type)

cufftXtClearCallback() 指示 cuFFT 在执行 plan 时停止调用指定的旧式回调类型。仅清除指定的回调。如果未指定此类型的回调,则返回代码为 CUFFT_SUCCESS

请注意,此方法不适用于 LTO 回调。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • type[In] – 回调例程的类型。

返回值

3.11.4. cufftXtSetCallbackSharedSize()

cufftResult cufftXtSetCallbackSharedSize(cufftHandle plan, cufftXtCallbackType type, size_t sharedSize)

cufftXtSetCallbackSharedSize() 指示 cuFFT 在启动时动态分配共享内存,以供回调使用。允许的最大共享内存量为 16K 字节。cuFFT 在执行时将指向此共享内存的指针传递给回调例程。此共享内存仅在加载或存储回调操作的生命周期内有效。在执行期间,cuFFT 可能会覆盖共享内存以用于其自身目的。

参数
  • plan[In] – 由 cufftCreate 返回的 cufftHandle

  • type[In] – 回调例程的类型。

  • sharedSize[In] – 请求的共享内存量。

返回值
  • CUFFT_SUCCESS – cuFFT 将使用指向请求的共享内存量的指针调用回调例程。

  • CUFFT_INVALID_PLANplan 参数不是有效的句柄,或者在 10.4.0 之前的 cuFFT 版本中,非默认流已与该计划关联

  • CUFFT_INTERNAL_ERROR – 检测到内部驱动程序错误。

  • CUFFT_ALLOC_FAILED – cuFFT 将无法分配请求的共享内存量。

3.12. cufftSetStream()

cufftResult cufftSetStream(cufftHandle plan, cudaStream_t stream);

将 CUDA 流与 cuFFT plan 关联。在 plan 执行期间进行的所有内核启动现在都通过关联的流完成,从而可以与其他流中的活动(例如数据复制)重叠。关联一直保持到 plan 被销毁或流通过另一次调用 cufftSetStream() 更改为止。

请注意,从 CUDA 11.2(cuFFT 10.4.0)开始,多 GPU plan 支持 cufftSetStream()。当将流与 plan 关联时,cufftXtMemcpy() 在多个 GPU 之间保持同步。对于 cuFFT 的先前版本,cufftSetStream() 将在多 GPU plan 中返回错误。

请注意,从 CUDA 12.2(cuFFT 11.0.8)开始,在多 GPU plan 上,stream 可以与任何 GPU 上的任何上下文关联。但是,使用来自不同上下文的流重复调用 cufftSetStream() 会产生很小的时间损失。当重复调用 cufftSetStream 使用来自同一 CUDA 上下文的流时,可以获得最佳性能。

参数
  • plan[In] – 要与流关联的 cufftHandle 对象。

  • stream[In] – 使用 cudaStreamCreate() 创建的有效 CUDA 流;对于默认流,使用 0

返回值
  • CUFFT_SUCCESS – 流已与 plan 关联。

  • CUFFT_INVALID_PLANplan 参数不是有效句柄,或者 plan 在 10.4.0 之前的 cuFFT 版本中是多 GPU 的。

3.13. cufftGetVersion()

cufftResult cufftGetVersion(int *version);

返回 cuFFT 的版本号。

参数
  • *version[In] – 指向版本号的指针。

  • *version[Out] – 包含版本号。

返回值

CUFFT_SUCCESS – cuFFT 已成功返回版本号。

3.14. cufftGetProperty()

cufftResult cufftGetProperty(libraryPropertyType type, int *value);

*value 中返回由动态链接的 CUFFT 库的 type 描述的属性的编号。

参数
  • type[In] – CUDA 库属性。

  • value[Out] – 包含请求属性的整数值。

返回值
  • CUFFT_SUCCESS – 属性值已成功返回。

  • CUFFT_INVALID_TYPE – 属性类型无法识别。

  • CUFFT_INVALID_VALUEvalueNULL

3.15. cuFFT 类型

3.15.1. 参数 cufftType

cuFFT 库支持复数和实数数据变换。cufftType 数据类型是 cuFFT 支持的变换数据类型的枚举。

typedef enum cufftType_t {
    CUFFT_R2C = 0x2a,  // Real to complex (interleaved)
    CUFFT_C2R = 0x2c,  // Complex (interleaved) to real
    CUFFT_C2C = 0x29,  // Complex to complex (interleaved)
    CUFFT_D2Z = 0x6a,  // Double to double-complex (interleaved)
    CUFFT_Z2D = 0x6c,  // Double-complex (interleaved) to double
    CUFFT_Z2Z = 0x69   // Double-complex to double-complex (interleaved)
} cufftType;

3.15.2. 变换方向的参数

cuFFT 库根据复指数项的符号定义正向和逆向快速傅里叶变换。

#define CUFFT_FORWARD -1
#define CUFFT_INVERSE 1

cuFFT 执行未归一化的 FFT;也就是说,对输入数据集执行正向 FFT,然后对结果集执行逆向 FFT,得到的数据等于输入,并按元素数量缩放。数据大小倒数的变换缩放留给用户自行决定执行。

3.15.3. 回调的类型定义

cuFFT 库支持单精度或双精度、实数或复数数据、加载或存储的所有组合的回调函数。这些在参数 cufftXtCallbackType 中枚举。

typedef enum cufftXtCallbackType_t {
    CUFFT_CB_LD_COMPLEX = 0x0,
    CUFFT_CB_LD_COMPLEX_DOUBLE = 0x1,
    CUFFT_CB_LD_REAL = 0x2,
    CUFFT_CB_LD_REAL_DOUBLE = 0x3,
    CUFFT_CB_ST_COMPLEX = 0x4,
    CUFFT_CB_ST_COMPLEX_DOUBLE = 0x5,
    CUFFT_CB_ST_REAL = 0x6,
    CUFFT_CB_ST_REAL_DOUBLE = 0x7,
    CUFFT_CB_UNDEFINED = 0x8
} cufftXtCallbackType;

3.15.3.1. LTO 回调的类型定义

LTO 回调函数原型和指针类型定义如下

typedef cufftComplex (*cufftJITCallbackLoadC)(void *dataIn, unsigned long long offset, void *callerInfo, void *sharedPointer);

typedef cufftDoubleComplex (*cufftJITCallbackLoadZ)(void *dataIn, unsigned long long offset, void *callerInfo, void *sharedPointer);

typedef cufftReal (*cufftJITCallbackLoadR)(void *dataIn, unsigned long long offset, void *callerInfo, void *sharedPointer);

typedef cufftDoubleReal(*cufftJITCallbackLoadD)(void *dataIn, unsigned long long offset, void *callerInfo, void *sharedPointer);


typedef void (*cufftJITCallbackStoreC)(void *dataOut, unsigned long long offset, cufftComplex element, void *callerInfo, void *sharedPointer);

typedef void (*cufftJITCallbackStoreZ)(void *dataOut, unsigned long long offset, cufftDoubleComplex element, void *callerInfo, void *sharedPointer);

typedef void (*cufftJITCallbackStoreR)(void *dataOut, unsigned long long offset, cufftReal element, void *callerInfo, void *sharedPointer);

typedef void (*cufftJITCallbackStoreD)(void *dataOut, unsigned long long offset, cufftDoubleReal element, void *callerInfo, void *sharedPointer);

请注意 offset 参数类型 (unsigned long long) 与旧式回调(使用 size_t)的区别。

3.15.3.2. 旧式回调的类型定义

旧式回调函数原型和指针类型定义如下

typedef cufftComplex (*cufftCallbackLoadC)(void *dataIn, size_t offset, void *callerInfo, void *sharedPointer);

typedef cufftDoubleComplex (*cufftCallbackLoadZ)(void *dataIn, size_t offset, void *callerInfo, void *sharedPointer);

typedef cufftReal (*cufftCallbackLoadR)(void *dataIn, size_t offset, void *callerInfo, void *sharedPointer);

typedef cufftDoubleReal(*cufftCallbackLoadD)(void *dataIn, size_t offset, void *callerInfo, void *sharedPointer);


typedef void (*cufftCallbackStoreC)(void *dataOut, size_t offset, cufftComplex element, void *callerInfo, void *sharedPointer);

typedef void (*cufftCallbackStoreZ)(void *dataOut, size_t offset, cufftDoubleComplex element, void *callerInfo, void *sharedPointer);

typedef void (*cufftCallbackStoreR)(void *dataOut, size_t offset, cufftReal element, void *callerInfo, void *sharedPointer);

typedef void (*cufftCallbackStoreD)(void *dataOut, size_t offset, cufftDoubleReal element, void *callerInfo, void *sharedPointer);

3.15.4. 其他 cuFFT 类型

3.15.4.1. cufftHandle

type cufftHandle

用于存储和访问 cuFFT plan 的句柄类型。用户在创建 cuFFT plan 后收到句柄,并使用此句柄执行 plan。

typedef unsigned int cufftHandle;

3.15.4.2. cufftReal

单精度浮点实数据类型。

typedef float cufftReal;

3.15.4.3. cufftDoubleReal

双精度浮点实数据类型。

typedef double cufftDoubleReal;

3.15.4.4. cufftComplex

单精度浮点复数据类型,由交错的实部和虚部组成。

typedef cuComplex cufftComplex;

3.15.4.5. cufftDoubleComplex

双精度浮点复数据类型,由交错的实部和虚部组成。

typedef cuDoubleComplex cufftDoubleComplex;

3.16. 常用类型

3.16.1. cudaDataType

cudaDataType 数据类型是 CUDA 库支持的类型的枚举。

typedef enum cudaDataType_t
{
        CUDA_R_16F= 2, // 16 bit real
        CUDA_C_16F= 6, // 16 bit complex
        CUDA_R_32F= 0, // 32 bit real
        CUDA_C_32F= 4, // 32 bit complex
        CUDA_R_64F= 1, // 64 bit real
        CUDA_C_64F= 5, // 64 bit complex
        CUDA_R_8I= 3,  // 8 bit real as a signed integer
        CUDA_C_8I= 7,  // 8 bit complex as a pair of signed integers
        CUDA_R_8U= 8,  // 8 bit real as an unsigned integer
        CUDA_C_8U= 9   // 8 bit complex as a pair of unsigned integers
} cudaDataType;

3.16.2. libraryPropertyType

libraryPropertyType 数据类型是库属性类型的枚举。(即,CUDA 版本 X.Y.Z 将产生 MAJOR_VERSION=XMINOR_VERSION=YPATCH_LEVEL=Z

typedef enum libraryPropertyType_t
{
        MAJOR_VERSION,
        MINOR_VERSION,
        PATCH_LEVEL
} libraryPropertyType;

4. 多 GPU 数据组织

本章介绍在执行多 GPU 变换之前和之后,数据如何在 GPU 之间分布。为简单起见,本章假设调用者已指定 GPU 0 和 GPU 1 来执行变换。

4.1. 批量变换的多 GPU 数据组织

对于批量变换,每个单独的变换都在单个 GPU 上执行。如果可能,批次会均匀分布在 GPU 之间。对于在 n 个 GPU 上执行的大小为 m 的批次,其中 m 不能被 n 整除,则前 m % n 个 GPU 将执行 \(\left\lfloor \frac{m}{n} \right\rfloor+\ 1\) 个变换。其余 GPU 将执行 \(\left\lfloor \frac{m}{n} \right\rfloor\) 个变换。例如,在 4 个 GPU 上执行的 15 个变换的批次中,前三个 GPU 将执行 4 个变换,最后一个 GPU 将执行 3 个变换。这种方法消除了 GPU 之间数据交换的需要,并且对于批次大小可被 GPU 数量整除的情况,可以实现接近完美的缩放。

4.2. 单个 2D 和 3D 变换的多 GPU 数据组织

在多个 GPU 上执行的单个变换需要将数据在 GPU 之间划分。然后执行分阶段进行。例如,对于 2 个 GPU,对于尺寸均匀的 2D 和 3D 变换,每个 GPU 执行 (rank - 1) 维度中一半的变换。然后在 GPU 之间交换数据,以便可以处理最后一个维度。

由于 2D 和 3D 变换支持除 2 的幂以外的其他大小,因此数据可能无法在 GPU 之间均匀分布。通常,对于 n 个 GPU 的情况,大小为 m 且不是 n 的倍数的维度将以如下方式分布:前 m % n 个 GPU 将为 2D 变换获得额外的行,为 3D 变换获得额外的平面。

例如,在 4 个 GPU 上进行 2D 变换,使用在 C 中声明为 data[x][y] 的数组,其中 x 为 65,y 为 99。表面在变换之前分布,使得 GPU 0 接收尺寸为 [17][99] 的表面,而 GPU 1...3 接收尺寸为 [16][99] 的表面。变换后,每个 GPU 再次具有表面的一部分,但在 y 维度上划分。GPU 0...2 具有尺寸为 [65][25] 的表面。GPU 3 具有尺寸为 [65][24] 的表面

对于 4 个 GPU 上的 3D 变换,请考虑在 C 中声明为 data[x][y][z] 的数组,其中 x 为 103,y 为 122,z 为 64。体积在变换之前分布,使得每个 GPU 0...2 接收尺寸为 [26][122][64] 的体积,GPU 3 接收尺寸为 [25][122][64] 的体积。变换后,每个 GPU 再次具有表面的一部分,但在 y 维度上划分。GPU 0 和 1 具有尺寸为 [103][31][64] 的体积,GPU 2 和 3 具有尺寸为 [103][30][64] 的体积。

4.3. 单个 1D 变换的多 GPU 数据组织

默认情况下,对于 1D 变换,数据到 GPU 的初始分布类似于 2D 和 3D 情况。对于两个 GPU 上维度为 x 的变换,GPU 0 接收范围从 0…(x/2-1) 的数据。GPU 1 接收范围从 (x/2)…(x-1) 的数据。类似地,对于 4 个 GPU,数据均匀分布在所有 4 个 GPU 之间。

在计算开始之前,数据在 GPU 之间重新分布。在应用程序不需要在变换之前预处理数据的情况下,可以在从主机内存复制时执行此重新分布。为此,应用程序可以使用子格式 CUFFT_XT_FORMAT_1D_INPUT_SHUFFLED 通过 cufftXtMalloc 创建数据描述符。这可以显着减少执行变换所需的时间。

cuFFT 通过将变换大小分解为因子 Factor1Factor2,并将数据视为大小为 Factor1 x Factor2 的网格来执行多 GPU 1D 变换。计算 1D FFT 的四个步骤是:大小为 Factor2Factor1 个变换、GPU 之间的数据交换、逐点旋转因子乘法以及大小为 Factor1Factor2 个变换。

为了通过将计算与数据交换重叠来提高效率,cuFFT 将整个变换分解为独立的段或字符串,这些段或字符串可以在其他段或字符串正在进行时进行处理。此算法的一个副作用是变换的输出不是线性顺序的。GPU 内存中的输出是字符串,每个字符串由 Factor2 个大小相等的子字符串组成。每个子字符串都包含从前一个子字符串开头 Factor1 个元素之后开始的连续结果。每个字符串从前一个字符串开头子字符串大小元素之后开始。字符串按顺序出现,前半部分在 GPU 0 上,后半部分在 GPU 1 上。请参见下面的示例

transform size = 1024
number of strings = 8
Factor1 = 64
Factor2 = 16
substrings per string for output layout is Factor2 (16)
string size = 1024/8 = 128
substring size = 128/16 = 8
stride between substrings = 1024/16 = Factor1 (64)

On GPU 0:
string 0 has substrings with indices 0...7   64...71   128...135 ... 960...967
string 1 has substrings with indices 8...15  72...79   136...143 ... 968...975
...
On GPU 1:
string 4 has substrings with indices 32...39  96...103 160...167 ... 992...999
...
string 7 has substrings with indices 56...63 120...127 184...191 ... 1016...1023

cufftXtQueryPlan API 允许调用者检索包含字符串数量、分解因子以及(在 2 的幂大小的情况下)一些有用的掩码和移位元素的结构。下面的示例显示了如何调用 cufftXtQueryPlan。它还显示了如何将主机输入数组中的索引转换为设备上的相应索引,反之亦然。

/*
 * These routines demonstrate the use of cufftXtQueryPlan to get the 1D
 * factorization and convert between permuted and linear indexes.
 */
/*
 * Set up a 1D plan that will execute on GPU 0 and GPU1, and query
 * the decomposition factors
 */
int main(int argc, char **argv){
    cufftHandle plan;
    cufftResult stat;
    int whichGPUs[2] = { 0, 1 };
    cufftXt1dFactors factors;
    stat = cufftCreate( &plan );
    if (stat != CUFFT_SUCCESS) {
        printf("Create error %d\n",stat);
        return 1;
    }
    stat = cufftXtSetGPUs( plan, 2, whichGPUs );
    if (stat != CUFFT_SUCCESS) {
        printf("SetGPU error %d\n",stat);
        return 1;
    }
    stat = cufftMakePlan1d( plan, size, CUFFT_C2C, 1, workSizes );
    if (stat != CUFFT_SUCCESS) {
        printf("MakePlan error %d\n",stat);
        return 1;
    }
    stat = cufftXtQueryPlan( plan, (void *) &factors, CUFFT_QUERY_1D_FACTORS );
    if (stat != CUFFT_SUCCESS) {
        printf("QueryPlan error %d\n",stat);
        return 1;
    }
    printf("Factor 1 %zd, Factor2 %zd\n",factors.factor1,factors.factor2);
    cufftDestroy(plan);
    return 0;
}
/*
 * Given an index into a permuted array, and the GPU index return the
 * corresponding linear index from the beginning of the input buffer.
 *
 * Parameters:
 *      factors     input:  pointer to cufftXt1dFactors as returned by
 *                          cufftXtQueryPlan
 *      permutedIx  input:  index of the desired element in the device output
 *                          array
 *      linearIx    output: index of the corresponding input element in the
 *                          host array
 *      GPUix       input:  index of the GPU containing the desired element
 */
cufftResult permuted2Linear( cufftXt1dFactors * factors,
                             size_t permutedIx,
                             size_t *linearIx,
                             int GPUIx ) {
    size_t indexInSubstring;
    size_t whichString;
    size_t whichSubstring;
    // the low order bits of the permuted index match those of the linear index
    indexInSubstring = permutedIx & factors->substringMask;
    // the next higher bits are the substring index
    whichSubstring = (permutedIx >> factors->substringShift) &
                      factors->factor2Mask;
    // the next higher bits are the string index on this GPU
    whichString = (permutedIx >> factors->stringShift) & factors->stringMask;
    // now adjust the index for the second GPU
    if (GPUIx) {
        whichString += factors->stringCount/2;
    }
    // linear index low order bits are the same
    // next higher linear index bits are the string index
    *linearIx = indexInSubstring + ( whichString << factors->substringShift );
    // next higher bits of linear address are the substring index
    *linearIx += whichSubstring << factors->factor1Shift;
    return CUFFT_SUCCESS;
}
/*
 * Given a linear index into a 1D array, return the GPU containing the permuted
 * result, and index from the start of the data buffer for that element.
 *
 * Parameters:
 *      factors     input:  pointer to cufftXt1dFactors as returned by
 *                          cufftXtQueryPlan
 *      linearIx    input:  index of the desired element in the host input
 *                          array
 *      permutedIx  output: index of the corresponding result in the device
 *                          output array
 *      GPUix       output: index of the GPU containing the result
 */
cufftResult linear2Permuted( cufftXt1dFactors * factors,
                             size_t linearIx,
                             size_t *permutedIx,
                             int *GPUIx ) {
    size_t indexInSubstring;
    size_t whichString;
    size_t whichSubstring;
    size_t whichStringMask;
    int whichStringShift;
    if (linearIx >= factors->size) {
        return CUFFT_INVALID_VALUE;
    }
    // get a useful additional mask and shift count
    whichStringMask = factors->stringCount -1;
    whichStringShift = (factors->factor1Shift + factors->factor2Shift) -
                        factors->stringShift ;
    // the low order bits identify the index within the substring
    indexInSubstring = linearIx & factors->substringMask;
    // first determine which string has our linear index.
    // the low order bits indentify the index within the substring.
    // the next higher order bits identify which string.
    whichString = (linearIx >> factors->substringShift) & whichStringMask;
    // the first stringCount/2 strings are in the first GPU,
    // the rest are in the second.
    *GPUIx = whichString/(factors->stringCount/2);
    // next determine which substring within the string has our index
    // the substring index is in the next higher order bits of the index
    whichSubstring = (linearIx >>(factors->substringShift + whichStringShift)) &
                      factors->factor2Mask;
    // now we can re-assemble the index
    *permutedIx = indexInSubstring;
    *permutedIx += whichSubstring << factors->substringShift;
    if ( !*GPUIx ) {
        *permutedIx += whichString << factors->stringShift;
    } else {
        *permutedIx += (whichString - (factors->stringCount/2) ) <<
                        factors->stringShift;
    }
    return CUFFT_SUCCESS;
}

5. FFTW 转换指南

cuFFT 与 FFTW 的不同之处在于,FFTW 有许多 plan 和一个执行函数,而 cuFFT 的 plan 较少,但执行函数更多。cuFFT 执行函数确定精度(单精度或双精度)以及输入是复数值还是实数值。下表显示了两个接口之间的关系。

FFTW 函数

cuFFT 函数

fftw_plan_dft_1d()fftw_plan_dft_r2c_1d()fftw_plan_dft_c2r_1d()

cufftPlan1d()

fftw_plan_dft_2d()fftw_plan_dft_r2c_2d()fftw_plan_dft_c2r_2d()

cufftPlan2d()

fftw_plan_dft_3d()fftw_plan_dft_r2c_3d()fftw_plan_dft_c2r_3d()

cufftPlan3d()

fftw_plan_dft()fftw_plan_dft_r2c()fftw_plan_dft_c2r()

cufftPlanMany()

fftw_plan_many_dft()fftw_plan_many_dft_r2c()fftw_plan_many_dft_c2r()

cufftPlanMany()

fftw_execute()

cufftExecC2C()cufftExecZ2Z()cufftExecR2C()cufftExecD2Z()cufftExecC2R()cufftExecZ2D()

fftw_destroy_plan()

cufftDestroy()

6. FFTW 到 cuFFT 的接口

NVIDIA 提供了到 cuFFT 库的 FFTW3 接口。这允许使用 FFTW 的应用程序使用 NVIDIA GPU,而只需对程序源代码进行最少的修改。要使用该接口,请首先执行以下两个步骤

  • 建议您将包含文件 fftw3.h 替换为 cufftw.h

  • 不要链接到双精度/单精度库(例如 fftw3/fftw3f 库),而是同时链接到 cuFFT 和 cuFFTW 库

  • 确保搜索路径包含包含 cuda_runtime_api.h 的目录

在应用程序使用 FFTW3 接口工作后,用户可能希望修改其代码以将数据移入和移出 GPU,并使用 FFTW 转换指南 中记录的例程以获得最佳性能。

下表显示了 cuFFT 中支持的 FFTW3 的组件和函数。

FFTW 手册中的章节

支持

不支持

复数

fftw_complex, fftwf_complex 类型

精度

双精度 fftw3,单精度 fftwf3

不支持长双精度 fftw3l、四精度 fftw3q,因为 CUDA 函数对双精度和单精度浮点量进行操作

内存分配

fftw_malloc()fftw_free()fftw_alloc_real()fftw_alloc_complex()fftwf_alloc_real()fftwf_alloc_complex()

多线程 FFTW

不支持 fftw3_threads, fftw3_omp

使用 MPI 的分布式内存 FFTW

不支持 fftw3_mpi,fftw3f_mpi

请注意,对于下面的每个双精度函数,都有一个相应的单精度版本,其中字母 fftw 替换为 fftwf

FFTW 手册中的章节

支持

不支持

使用 Plan

fftw_execute()fftw_destroy_plan()fftw_cleanup()

fftw_print_plan()fftw_cost()fftw_flops() 存在但不 functional

基本接口

复数 DFT

fftw_plan_dft_1d()fftw_plan_dft_2d()fftw_plan_dft_3d()fftw_plan_dft()

Planner 标志

Planner 标志被忽略,并且无论如何都返回相同的 plan

实数据 DFT

fftw_plan_dft_r2c_1d()fftw_plan_dft_r2c_2d()fftw_plan_dft_r2c_3d()fftw_plan_dft_r2c()fftw_plan_dft_c2r_1d()fftw_plan_dft_c2r_2d()fftw_plan_dft_c2r_3d()fftw_plan_dft_c2r()

实数据 DFT 数组格式

不支持

实到实变换

不支持

实到实变换类型

不支持

高级接口

高级复数 DFT

具有多个 1D、2D、3D 变换的 fftw_plan_many_dft()

具有 4D 或更高维度变换或 2D 或更高维度嵌入式变换批次的 fftw_plan_many_dft()

高级实数据 DFT

具有多个 1D、2D、3D 变换的 fftw_plan_many_dft_r2c()fftw_plan_many_dft_c2r()

具有 4D 或更高维度变换或 2D 或更高维度嵌入式变换批次的 fftw_plan_many_dft_r2c()fftw_plan_many_dft_c2r()

高级实到实变换

不支持

Guru 接口

交错和分离数组

交错格式

拆分格式

Guru 向量和变换大小

fftw_iodim 结构体

Guru 复数 DFT

fftw_plan_guru_dft()、 fftw_plan_guru_dft_r2c()、 fftw_plan_guru_dft_c2r(),具有多个 1D、2D、3D 变换

fftw_plan_guru_dft()、 fftw_plan_guru_dft_r2c()、 fftw_plan_guru_dft_c2r(),具有 4D 或更高维度的变换或 2D 或更高维度的批量变换

Guru 实数据 DFT

不支持

Guru 实数到实数变换

不支持

64 位 Guru 接口

fftw_plan_guru64_dft()、 fftw_plan_guru64_dft_r2c()、 fftw_plan_guru64_dft_c2r(),具有多个 1D、2D、3D 变换

fftw_plan_guru64_dft()、 fftw_plan_guru64_dft_r2c()、 fftw_plan_guru64_dft_c2r(),具有 4D 或更高维度的变换或 2D 或更高维度的批量变换

新数组执行函数

fftw_execute_dft()、 fftw_execute_dft_r2c()、 fftw_execute_dft_c2r(),具有交错格式

拆分格式和实数到实数函数

智慧

fftw_export_wisdom_to_file()、 fftw_import_wisdom_from_file() 存在但不起作用。其他智慧函数在库中没有入口点。

7. 已弃用的功能

从 CUDA 12.0 开始

  • 不再支持 GPU 架构 SM35 和 SM37。最低要求的架构是 SM50。

从 CUDA 11.8 开始

  • 对于以异地模式变换加载数据的旧式回调例程,不再支持 CUDA Graphs 捕获。从 CUDA 12.6 Update 2 开始,LTO 回调可以用作旧式回调的替代方案,而没有此限制。

从 CUDA 11.4 开始

  • 在所有 GPU 架构上,已弃用使用单独编译的设备代码(旧式回调)的回调功能。所有 GPU 架构将继续支持回调功能。

从 CUDA 11.0 开始

  • 不再支持 GPU 架构 SM30。最低要求的架构是 SM35。

  • 已弃用对 GPU 架构 SM35、SM37 (Kepler) 以及 SM50、SM52 (Maxwell) 的支持。

函数 cufftSetCompatibilityMode 在 9.1 版本中已移除。

8. 声明

8.1. 声明

本文档仅供参考,不应视为对产品的特定功能、条件或质量的保证。NVIDIA Corporation(“NVIDIA”)对本文档中包含的信息的准确性或完整性不作任何明示或暗示的陈述或保证,并且对本文档中包含的任何错误不承担任何责任。NVIDIA 对使用此类信息或因使用此类信息而可能导致的侵犯第三方专利或其他权利的后果或使用不承担任何责任。本文档不承诺开发、发布或交付任何材料(如下定义)、代码或功能。

NVIDIA 保留随时对此文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。

客户应在下订单前获取最新的相关信息,并应验证此类信息是否为最新且完整。

NVIDIA 产品根据订单确认时提供的 NVIDIA 标准销售条款和条件进行销售,除非 NVIDIA 和客户的授权代表签署的个别销售协议(“销售条款”)另有约定。NVIDIA 在此明确反对将任何客户通用条款和条件应用于购买本文档中引用的 NVIDIA 产品。本文档未直接或间接地形成任何合同义务。

NVIDIA 产品并非设计、授权或保证适用于医疗、军事、航空、航天或生命支持设备,也不适用于 NVIDIA 产品的故障或失灵可能合理预期会导致人身伤害、死亡或财产或环境损害的应用。NVIDIA 对在上述设备或应用中包含和/或使用 NVIDIA 产品不承担任何责任,因此,此类包含和/或使用由客户自行承担风险。

NVIDIA 不保证或声明基于本文档的产品将适用于任何特定用途。NVIDIA 不一定对每种产品的所有参数进行测试。客户全权负责评估和确定本文档中包含的任何信息的适用性,确保产品适合并满足客户计划的应用,并为该应用执行必要的测试,以避免应用或产品的默认设置。客户产品设计中的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的附加或不同的条件和/或要求。对于可能基于或归因于以下原因的任何默认设置、损坏、成本或问题,NVIDIA 不承担任何责任:(i) 以任何违反本文档的方式使用 NVIDIA 产品或 (ii) 客户产品设计。

本文档未授予任何 NVIDIA 专利权、版权或其他 NVIDIA 知识产权下的任何明示或暗示的许可。NVIDIA 发布的有关第三方产品或服务的信息不构成 NVIDIA 授予使用此类产品或服务的许可,也不构成对其的保证或认可。使用此类信息可能需要从第三方获得其专利或其他知识产权下的许可,或从 NVIDIA 获得 NVIDIA 专利或其他知识产权下的许可。

只有在事先获得 NVIDIA 书面批准的情况下,才允许复制本文档中的信息,并且复制必须未经修改且完全符合所有适用的出口法律和法规,并附带所有相关的条件、限制和声明。

本文档和所有 NVIDIA 设计规范、参考板、文件、图纸、诊断程序、列表和其他文档(统称为“材料”,单独称为“材料”)均“按现状”提供。NVIDIA 对材料不作任何明示、暗示、法定或其他方面的保证,并明确否认所有关于不侵权、适销性和特定用途适用性的暗示保证。在法律未禁止的范围内,在任何情况下,NVIDIA 均不对因使用本文档而引起的任何损害(包括但不限于任何直接、间接、特殊、附带、惩罚性或后果性损害,无论如何造成,也无论责任理论如何)承担责任,即使 NVIDIA 已被告知可能发生此类损害。尽管客户可能因任何原因遭受任何损害,NVIDIA 对本文所述产品的客户的累计和累积责任应根据产品的销售条款进行限制。

8.2. OpenCL

OpenCL 是 Apple Inc. 的商标,经 Khronos Group Inc. 许可使用。

8.3. 商标

NVIDIA 和 NVIDIA 徽标是 NVIDIA Corporation 在美国和其他国家/地区的商标或注册商标。其他公司和产品名称可能是与其相关的各自公司的商标。