CPU的目的是提供高性能的数字运算,最终得到某种矢量指令集.基本上有两种:
有人认为备选案文2更好,这些论点似乎是有道理的,例如https://www.sigarch.org/simd-instructions-considered-harmful/
至少乍一看,选项2似乎可以做选项1所能做的所有事情,更容易,而且通常更好。
是否存在反向为真的工作负载?哪里的SIMD指令可以做的事情,克雷风格的向量不能,或可以做一些更快或用较少的代码?
发布于 2022-06-03 17:23:47
传统的矢量方法(Cray、CDC/ETA、NEC等)产生于一个晶体管预算有限和市场上可用的低延迟SRAM主存储器的时代(1976年~1992年)。在这种技术模式下,处理器没有晶体管预算来实现当前允许流水线的多周期浮点操作的无序操作的全部记分板和联锁。相反,创建了一个矢量指令集。矢量算术指令保证了向量内的连续操作是独立的,并且可以是流水线的。将硬件扩展到允许并行多个向量操作相对容易,因为依赖性检查只需要“每个向量”而不是“每个元素”。
Cray ISA类似于RISC,因为数据从内存加载到矢量寄存器,算法执行寄存器到寄存器,然后将结果从矢量寄存器存储回内存。最大向量长度最初为64个元素,后来为128个元素。
CDC/ETA系统采用“内存到内存”的体系结构,算术指令指定所有输入和输出的内存位置,矢量长度为1到65535元素。
没有一个“传统”向量机器使用数据缓存来进行向量操作,因此性能受到从内存加载数据的速度的限制。SRAM主要存储器是系统成本的一小部分。20世纪90年代初,SRAM的成本/位仅是DRAM的2倍,但DRAM的价格下降得如此之快,以至于到2002年,SRAM /MiB的价格是DRAM的75倍--甚至已经不能再被接受了。
传统机器的SRAM存储器是字可寻址的(64位字),并且非常大量地存储以使线性、跨步(只要避免二次幂)和随机访问的速度接近全速。这导致了一种编程风格,它广泛使用了非单元式内存访问模式。这些访问模式在缓存的机器上造成性能问题,随着时间的推移,使用缓存系统的开发人员不再使用它们--因此代码无法利用矢量系统的这种能力。在重新编写代码以使用缓存系统时,缓存对于在向量机上运行的大多数应用程序来说都是很好的。缓存数据的重复使用减少了所需的内存带宽,因此应用程序在基于微处理器的系统上运行得比从主内存带宽比率中预期的要好得多。
到了20世纪90年代末,传统向量机的市场几乎没有了,工作负载主要转移到使用RISC处理器和多级缓存层次结构的共享内存机器。一些政府补贴的矢量系统已经开发出来(特别是在日本),但是这些系统对高性能的计算几乎没有影响,对一般的计算也没有影响。
故事还没有结束--在许多不太成功的尝试(由几个供应商)成功地让向量和缓存一起工作之后,NEC开发了一个非常有趣的系统(NEC SX-Aurora Tsubasa),它将多核矢量寄存器处理器设计与DRAM (HBM)主存和一个有效的共享缓存结合起来。我特别喜欢使用一个执行线程产生超过300 GB/s内存带宽的能力--这是一个带有AMD或Intel处理器的线程的带宽的10x-25倍。
所以答案是,即使在SIMD还没有包括之前,带有缓存内存的微处理器的低成本就把向量机赶出了市场。SIMD对于特定的专业操作有着明显的优势,并且随着时间的推移变得更加普遍--尽管随着SIMD宽度的增加,它带来的好处越来越少。在体系结构意义上,向量方法并不是死的(例如NEC向量引擎),但它的优点通常被软件与主流体系结构模型不兼容的缺点所淹没。
发布于 2022-05-29 09:57:10
Cray型向量对于纯垂直问题是很好的,有些人认为SIMD仅限于这类问题。它们使您的代码向前与具有更宽向量的未来CPU兼容。
我从来没有使用过Cray风格的向量,所以我不知道有多大的空间可以让它们进行水平的洗牌。
如果你不把事情具体限制在Cray上,现代指令集(如ARM SVE和RISC-V分机 )也会给出具有可变矢量宽度的前向兼容代码,并且显然是为了避免像AVX2和AVX-512这样的短固定向量SIMD ISAs和ARM NEON的问题。
我觉得他们有洗牌的能力。当然是掩蔽,但我还不太熟悉他们,不知道他们是否可以做一些事情,如左包(AVX2基于掩码的最有效的打包方法是什么?)或前缀和(带SSE的并行前缀(累积)和)。
还有一些问题,就是一次只处理少量固定的数据,但不只是在一个整数寄存器中。例如,如何将二进制整数转换为十六进制字符串?,尽管在一些初始广播之后,它仍然对每个元素做同样的事情。
但是其他一些东西,比如将9个字符数字转换为int或unsigned int的最快速的方法,一次过的自定义洗牌和水平成对的乘法,只需几个简单的uop指令就可以完成正确的工作,这需要在SIMD和核心的整数部分(如在x86 CPU上)之间进行紧密的集成,才能获得最大的性能。使用SIMD部分来完成它擅长的工作,然后将向量的低两个32位元素放入一个整数寄存器中,用于其余的工作。Cray模型的一部分(我认为)是与CPU管道的松耦合;这将击败类似的用例。虽然有些32位ARM CPU与霓虹灯有着同样的松耦合,但从矢量到整数的运动是缓慢的。
一般来说,解析文本和atoi是一个用例,在这种用例中,具有混叠功能的短向量是有效的。例如,https://www.phoronix.com/scan.php?page=article&item=simdjson-avx-512&num=1 - 25%到40%的加速速度从AVX-512和Simdjson2.0用于解析AVX2,超过了AVX2 SIMD的快速性能。(有关2016年将SIMD用于JSON的问答,请参见如何用SIMD实现atoi? )。
这些技巧中有许多依赖于x86特定的pmovmskb eax, xmm0
来获得向量比较结果的整数位图。例如,您可以测试是否全部为零或全部-1 (cmp eax, 0xffff
)停留在memcmp
或memchr
循环的主循环中。如果不是,那么bsf eax,eax
找出第一个差异的位置,可能在not
之后。
将矢量宽度限制在一个整数寄存器中的元素数是关键,尽管你可以想象一个指令集具有可伸缩宽度掩码寄存器的比较掩码。(也许ARM SVE已经是这样了?(我不确定。)
https://stackoverflow.com/questions/72422491
复制相似问题