CUDA核心有矢量指令吗?

时间:2018-01-19 16:03:22

标签: cuda opencl gpu nvidia gpgpu

根据大多数NVidia文档,CUDA核心是标量处理器,应该只执行标量操作,这将被矢量化为32分量SIMT扭曲。

但是OpenCL具有矢量类型,例如uchar8。它具有与ulong(64位)相同的大小,可以由单个标量核处理。如果我对uchar8向量进行操作(例如组件添加),它是否也会映射到单个核心上的指令?

如果一个块(工作组)中有1024个工作项,并且每个工作项处理一个uchar8,这是否会有效地并行处理8120 uchar

修改 我的问题是,如果在CUDA架构上(独立于OpenCL),有一些矢量指令可用于"标量"核心。因为如果核心已经能够处理32位类型,那么例如它也可以处理32位uchar4的添加是合理的,特别是因为向量操作经常用在计算机图形中。 / p>

2 个答案:

答案 0 :(得分:7)

CUDA内置"内置" (即预定义的)矢量类型,对于4字节量(例如int4)最大为4,对于8字节量(例如double2)最大为2。 CUDA线程的最大读/写事务大小为16字节,因此这些特定大小的选择往往与that maximum对齐。

这些是作为典型结构公开的,因此您可以引用例如.x来仅访问矢量类型的第一个元素。

与OpenCL不同,CUDA不提供基本算法的内置操作("重载"),例如+-等,用于对这些矢量类型进行逐元素操作。没有特别的理由你不能自己提供这样的超载。同样,如果您想要uchar8,您可以轻松地为此类提供结构定义,以及任何所需的运算符重载。这些可能正如您对普通C ++代码所期望的那样实现。

那么,潜在的问题可能是,在这方面,CUDA和OpenCL之间的实施有何不同?如果我使用uchar8,例如

uchar8 v1 = {...};
uchar8 v2 = {...};
uchar8 r = v1 + v2;

OpenCL和CUDA之间的机器性能(或低级代码生成)有何不同?

对于支持CUDA的GPU,可能并不多。 CUDA核心(即底层ALU)对uchar8上的此类操作没有直接的本机支持,而且,如果编写自己的C ++兼容重载,您可能会使用C ++语义对于这本身就是连续的:

r.x = v1.x + v2.x;
r.y = v1.y + v2.y;
...

因此,这将分解为在CUDA核心上执行的一系列操作(或在CUDA SM内的适当整数单元中)。由于NVIDIA GPU硬件并未在单核/时钟/指令内为8路uchar添加提供任何直接支持,因此OpenCL(在NVIDIA GPU上实现)可能不会太多不同。在较低级别,底层机器代码将是一系列操作,而不是单个指令。

另外,CUDA(或PTX或CUDA内在函数)确实在单个核心/线程/指令中提供有限数量的向量运算。一些例子是:

  1. 一组有限的" native" "video" SIMD instructions。这些指令是每个线程,因此如果使用,它们允许" native"尽管操作数必须正确地打包到32位寄存器中,但每个warp最多支持4x32 = 128(8位)操作数。您可以通过一组内置的intrinsics直接从C ++访问这些内容。 (CUDA warp 是一组32个线程,是支持CUDA的GPU上锁步并行执行和调度的基本单位。)

  2. 向量(SIMD)乘法 - 累加运算,它不能直接转换为单个特定元素运算过载,即所谓的int8 dp2a和dp4a指令。 int8这里有点误导。它不是指int8向量类型,而是在单个32位字/寄存器中的4个8位整数量的打包排列。同样,可以通过intrinsics访问这些内容。

  3. 对于某些操作,在cc 5.3及更高版本的GPU中通过half2向量类型本机支持16位浮点。

  4. 新的Volta tensorCore模糊地类似于每线程SIMD操作,但它在一组16x16输入矩阵上运行(warp-wide),产生16x16矩阵结果。

  5. 即使使用智能OpenCL编译器,它也可以将某些矢量操作映射到各种操作中。本地"由硬件支持,它不会完全覆盖。在单个指令中,单个核心/线程上的8宽向量(例如uchar8)没有操作支持来选择一个示例。因此有必要进行一些序列化。在实践中,我不认为NVIDIA的OpenCL编译器是那么聪明,所以我期望你会发现这样的每线程向量操作完全序列化,如果你研究了机器代码。

    在CUDA中,您可以为某些操作和矢量类型提供自己的重载,这些操作和矢量类型大致可以在单个指令中表示。例如,可以执行uchar4添加"本地"使用__vadd4() intrinsic(可能包含在运算符重载的实现中)。同样,如果您编写自己的运算符重载,我不认为执行uchar8元素是很困难的使用两条__vadd4()指令添加矢量。

答案 1 :(得分:-1)

  

如果我对uchar8向量进行操作(例如组件添加),它是否也会映射到单个核心上的指令?

AFAIK它总是在一个核心上(来自单个内核/工作项的指令不会跨越核心,除了像障碍这样的特殊指令),但它可能不止一条指令。这取决于您的硬件是否支持uchar8本地操作。如果没有,则uchar8将根据需要分解为多个部分,并且每个部分将使用单独的指令进行处理。

OpenCL非常“通用”,因为它支持许多不同的矢量类型/大小组合,但实际硬件通常只实现一些矢量类型/大小组合。您可以查询OpenCL设备的“首选矢量大小”,它应该告诉您该硬件的效率最高。