2017-07-31 87 views
0

我正在准备参加考试,并且正在做一些没有帮助的练习。所以我一直在给这个代码,并想知道我是否已将代码转换为SIMD指令。使用SIMD指令将代码转换为代码

代码

int A[100000]; 
int B[100000]; 
int C=0; 

for int(i=0; i < 100000; i++) 
    C += A[i] * B[i]; 

由于没有余,我们并不需要照顾它。我们还假定它是一个128位寄存器,因此可以计算4个单精度浮点值。

我的结果 - 使用SIMD

int A[100000]; 
int B[100000]; 
int C=0; 

for int(i=0; i < 100000/4; i += 4) 
    C += A[i] * B[i]; 
    C += A[i+1] * B[i+1]; 
    C += A[i+2] * B[i+2]; 
    C += A[i+3] * B[i+3]; 

你可以看到使用SIMD指令,而不是写多线程程序有什么优势?

回答

1

假设第二个循环中省略的花括号仅仅是一个错字,并且在for循环中有一个错字,并且您询问了乘法浮点数的问题,但是您的代码显示了整数数组,这样甚至不会获得很好的向量化如果编译器看到它。虽然编译器可能会将来自A和B的4个值加载为单个指令,并在一条指令中执行4次乘法,但代码会强制编译器提取4个产品中的每一个,然后依次对它们进行求和,并逐个获取SIMD寄存器中的值通常很慢。

如果在另一方面,你这样做

float A[100000]; 
float B[100000]; 
float C0=0, C1=0, C2=0, C3=0; 

for (size_t i=0; i < 100000/4; i += 4) 
{ 
    C0 += A[i+0] * B[i+0]; 
    C1 += A[i+1] * B[i+1]; 
    C2 += A[i+2] * B[i+2]; 
    C3 += A[i+3] * B[i+3]; 
} 
float C = (C0 + C1) + (C2 + C3); 

然后一个很好的编译器可以像现在vectorise这个它认为每个循环中它加载两个SIMD寄存器,它们相乘,则可以添加结果一个SIMD寄存器的总和,并且只提取这4个数字并且在最后总计它们。

矢量化编译可以用SIMD来做到这一点,它不会改变个别和的评估顺序(FP数学不是关联的)。由于这个原因,编译器通常不被允许改变FP数学的顺序(不是没有一些额外的标志允许它在技术上违反语言标准),所以上面的代码可以用SIMD指令精确地表示,并且运行得更快(事实上​​我会放松循环,因为乘法会成为瓶颈)。

这是SIMD的一个技巧,你必须理解,然后思考如何用矢量指令最好地实现该操作,然后编写代码来执行相同的操作序列,并希望编译器能够找到你已经完成了。

或者你也可以用intrinsics自己编写矢量指令,或者使用OpenMP或类似的方式来更明确地告诉编译器该做什么。

SIMD优于线程这种操作的优势在于,您正在单个内核中使用更多的硅片......因此您不会阻止另一个线程获取周期。在我们的计算网格中,我们通常在任何一台机器上运行多个单线程进程,以保持所有内核在任何时候都处于繁忙状态......在这种情况下,使用更多内核来实现这一点是一种虚假的经济,您只需要窃取另一个线程可能会有用地运行另一项工作。

1

是的,所提供的代码应该编译成带有能力的CPU和编译器的SIMD指令。

在支持向量的处理器上,SIMD公开了硬件特性,这些特性极大地加速了相同的并行计算。例如,由于流式RAM访问,SIMD通常更好地利用单个内核上的缓存,假设正在处理的数据本地化在连续的内存区域中。使用多处理,缓存竞争和其他同步开销实际上可能会降低性能,因为各种核心试图同时写入数据。除了von-Neumann机器的内在增强之外,它只需要从共享系统存储器中读取一条而不是四条单独的指令。

并行执行这些算术运算的逻辑总是存在,但需要使用特定的SIMD指令。因此,SIMD倾向于用于手动调节使整体优化更有意义的热循环中。

+0

那么,矢量化优化器可能会或者很多都不会优化任一循环,但在考试环境中,我期望看到更加明确的映射到底层架构,以阐明学生已经理解了系统的原理。特别是水平加法应该在最后进行最终折叠时作为矢量加法执行,特别是由于缺乏关联性,可能会禁止等效的浮点格式。为了避免优化器阻塞代码复杂性,阵列的显式对齐规范也不会受到影响。 – doynax

+0

对于考试,我希望看到这个手工编码的目标架构的程序集,说实话。给定一个中途体面的编译器,尽管这个代码应该最终被优化(在过去做了一些类似的HPC矢量,并验证了GCC的汇编输出)。 OP应该明确地分解二进制文件并检查SIMD指令...... – madscientist159

+0

同意,内在函数将成为这里的一种方式,并且优化编译器可以使用纠结的代码创造奇迹(相反,随机分解出于难理解的原因)。在这里最让我困扰的是提到了“单精度浮点值”,在这种情况下,将'int'替换为'float',剩下一个固有的串行依赖链,用于累积,除非使用像' - 快速数学“,并打破了过程中的大部分数字算法。老实说,除非使用并行累积缓冲区,否则我无法在考试中看到答案被接受。 – doynax