CUDA核心有矢量指令吗?

tml*_*len 3 cuda gpu gpgpu nvidia opencl

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

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

如果一个块(工作组)中有1024个工作项,并且每个工作项处理一个uchar8,那么这将有效地uchar并行处理8120 吗?

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

Rob*_*lla 8

对于4字节数量(例如int4),CUDA具有"内置"(即预定义)矢量类型,最大尺寸为4,对于8字节数量(例如),最大尺寸为2 double2.CUDA线程的最大读/写事务大小为16字节,因此这些特定大小的选择倾向于与该最大值对齐.

它们作为典型结构公开,因此您可以参考例如.x仅访问矢量类型的第一个元素.

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

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

uchar8 v1 = {...};
uchar8 v2 = {...};
uchar8 r = v1 + v2;
Run Code Online (Sandbox Code Playgroud)

在OpenCL和CUDA之间的机器性能(或低级代码生成)方面会有什么不同?

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

r.x = v1.x + v2.x;
r.y = v1.y + v2.y;
...
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  3. half2对于某些操作,在cc 5.3和更高GPU中通过矢量类型本地支持16位浮点.

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

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

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