SIMD是否需要多核CPU?

9

在实现SIMD时是否需要多核CPU?

当我阅读维基百科关于SIMD的文章时,我发现了“多个处理元素”这一短语。那么这个短语和“多核CPU”有什么区别呢?

enter image description here


9
“SI”代表单条指令,“MD”代表多个数据。该核心需要有4个乘法电路可用,以便单条指令可以同时乘以4个数字。并行性在核心本身中实现。 - Hans Passant
1
@ShreckYe 我认为问题的意图是实现SIMD是否需要多核CPU,而不是多核CPU是否需要SIMD。原始文本语法混乱,需要修正,但你选择了与答案不符的另一种解释。(我编辑过,使其表达的问题与答案相符合。) - Peter Cordes
@PeterCordes 已经明白了。感谢您的指出。 - Shreck Ye
3个回答

12
每个核心都有自己独立的SIMD执行单元。在一个核心中使用SIMD指令不会消耗其他核心的执行资源。即使是在同一物理芯片上的独立核心也是独立的,因此它们可以单独进入睡眠状态以节省电力,并且有各种其他设计原因来保持它们隔离。
我知道的一个例外是:AMD Bulldozer有两个弱整数核心共享一个SIMD / FPU和一些缓存。他们称之为“集群”,基本上是超线程(SMT)的替代品。请参见David Kanter在RealworldTech上关于Bulldozer的文章
SIMD和多核是正交的:您可以拥有没有SIMD的多核(可能是一些没有FPU / NEON的ARM芯片),也可以拥有没有多核的SIMD。
许多后者的例子,包括最突出的早期x86芯片,如Pentium-MMX到Pentium III / Pentium 4,具有MMX / SSE1 / SSE2,但是是单核CPU。

程序中至少有三种不同的并行方式:

  • 指令级并行性: 可以重叠在同一线程内执行的不同指令的部分工作,保持运行每个指令一个接一个的幻觉。通过构建流水线CPU核心、超标量(multiple instructions per clock),甚至乱序执行来利用它。 (有关详细信息,请参见我在关于此问题的回答)。

    创建软件时:尽可能避免长依赖链,将此并行性暴露给硬件。(例如,使用多个累加器展开sum += a [i ++],而不是sum1+=a[i]; sum2+=a[i+1]; i+=2;:)或者使用数组而不是链接列表,因为要加载的下一个地址可以便宜地计算,而不是成为您在缓存未命中时必须等待的内存数据的一部分。但是大多数情况下,ILP已经存在于“正常”代码中,无需进行任何特殊处理,您可以构建更大/更高级的硬件来找到更多的ILP,并增加每个时钟的平均指令数。

  • 数据并行性: 您需要对图像的每个像素或音频文件中的每个样本执行相同的操作。(例如,混合2个图像或混合两个音频流)。通过在每个CPU核心中构建并行执行单元来利用此功能,因此单个指令可以并行执行16个单字节加法,从而使您的吞吐量增加而不需要增加每个时钟要通过CPU核心的指令数量。这就是SIMD:单指令多数据。

    音频/视频是最知名的应用程序,其中速度提升是巨大的,因为您可以将许多字节或16位元素放入单个固定宽度的向量寄存器中。

    使用智能编译器自动矢量化循环,或手动利用SIMD。 SIMD将sum += a[i];转换为sum[0..3] += a[i+0..3](对于每个向量4个元素,例如具有32位向量的intfloat)。

  • 线程/任务级并行性: 利用多核CPU,通过手动编写多线程代码或使用OpenMP或其他自动并行化工具将循环多线程化,或使用启动多个线程的库函数进行大型矩阵乘法等操作来暴露给硬件。

    或者更简单地同时运行多个单独的程序。例如,使用make -j8编译,以保持8个编译进程同时运行。粗粒度的任务级并行性也可以通过在多台计算机上运行工作负载来利用,甚至是分布式计算。

    但是,多核CPU使得可能/有效地利用细粒度的线程级并行性,其中任务需要共享大量数据(例如大型数组),或通过共享内存进行低延迟通信。(例如,使用锁来保护共享数据的不同部分,或无锁编程)

这三种并行性是正交的。
为了在现代CPU上汇总一个非常大的float数组:
您将为每个CPU核心启动一个线程,并使每个核心在共享内存中循环一块数组(线程级并行性)。这给您带来了4倍的加速,假设如此。(即使由于内存瓶颈而不太现实,但您可以想象一些其他计算密集型任务,它不需要读取太多内存,在28核Xeon或具有两个这些芯片的双插槽服务器上运行...)
每个线程的代码将使用SIMD在每个核心上分别执行4或8个加法操作。这使您获得4或8倍的加速。(使用AVX512则为16倍)
您将展开,使用8个向量累加器来隐藏浮点加法的延迟。(指令级并行性)。Skylake的vaddps指令的延迟为4个周期,吞吐量为0.5个周期(即每个时钟2个)。因此,8个累加器刚好足以隐藏该延迟并保持8个FP加法指令同时进行。
单线程标量sum += a[i++]的总吞吐量增益是所有加速因子的乘积:4 * 8 * 8 = 非并行化、非向量化、单累加器ILP瓶颈天真实现的吞吐量的256倍,例如你从简单循环中得到的gcc -O2clang -O3 -march=native -ffast-math将提供SIMD和一些ILP(因为clang知道如何在展开时使用多个累加器,通常使用4个,而不像gcc。)
您需要OpenMP或其他自动并行化来利用多个核心。
相关:为什么Haswell上的mulss只需要3个周期,与Agner的指令表不同?深入了解多个累加器的ILP和SIMD,以进行FMA循环。

相关:AVX/AVX2是否存在于每个核心上?(是的)。 - Peter Cordes
更正:通常情况下,“数据并行性”被定义为在许多元素上执行相同的工作。正如我在答案后面所讨论的那样,您可以使用ILP、SIMD和线程来利用这种数据并行性。因此,中间的项目应该是“SIMD并行性”,以便在指令流水线中每个槽位完成更多的工作。 - Peter Cordes

7
不,每个核心通常可以执行大部分指令集中的通用操作。但是针对SIMD操作的“多处理单元”只对不同的数据(不同的字节或单词)执行单个操作。
例如,ARM Cortex-A53微架构的每个核心都有能力独立运行SIMD指令,而像MMXSSESSE2等SIMD指令集最初是在单核CPU上引入的。

-2

是的,它确实有用。但仅从营销角度来看。如果没有SIMD指令,将很难销售uP或uC。


1
你最后一句话没有意义。例如,AVR微控制器是单核的,没有SIMD。你是不是想说销售带有SIMD的单核CPU很难?这在现今有点真实,但英特尔肯定很乐意销售奔腾-MMX(他们的第一个SIMD CPU,也是任何主流CPU中最早的SIMD实现之一)。我仍然记得他们在色彩缤纷的洁净室“兔子”服装中的广告活动https://www.intel.com/pressroom/archive/releases/1997/CN12297A.HTM,并搜索“intel pentium mmx ads”。SIMD比多核主流CPU早了几年。 - Peter Cordes
AVR是现代的还是多核的?8051也不是 :). 没有SIMD指令的现代单核或多核uP或uC设计将不会被老板接受,因为用户需要它们(在uC中用于DSP)。 - 0___________
但即使在现今,例如ARM Cortex-A17,也有1到4核配置可用,带有整数/浮点SIMD的NEON。我认为即使在低端芯片中,NEON指令也并不是完全罕见的。它可以让每个指令复制更多的内存,在简单的顺序执行芯片上这很重要。 - Peter Cordes
1
我没有做过太多嵌入式的东西,对于不同微控制器的功耗/速度/成本权衡并不了解。我主要在SO上看到有关它们的汇编问题,并出于兴趣阅读。我发现为什么Atmel AVR如此受欢迎?这篇文章很有趣。它似乎比ARM更适合低功耗应用,但一些评论者说它们更适合业余爱好者,商业设计更常使用PIC或MSP430。 - Peter Cordes
1
我现在给这个点了个踩,因为我认为你误读了问题。我认为OP问的是SIMD是否需要多核心,而不是多核CPU是否需要SIMD。(即他们不理解线程级并行性与数据级并行性的区别)。就像我已经说过多次的那样,你回答的是问题的相反面。(此外,显然有一些没有SIMD的处理器销售量不可忽略;显然人们想要它们用于非常低端的爱好项目,比如AVR,或者运行没有自动向量化和没有手动向量化的代码。) - Peter Cordes
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接