gpt4 book ai didi

fortran - fortran循环的simd向量长度和展开因子

转载 作者:行者123 更新时间:2023-12-02 16:55:16 25 4
gpt4 key购买 nike

我想使用SIMD指令矢量化下面的fortran

!DIR$ SIMD
DO IELEM = 1 , NELEM
X(IKLE(IELEM)) = X(IKLE(IELEM)) + W(IELEM)
ENDDO


我使用了指令avx2。该程序由

ifort main_vec.f -simd -g -pg -O2 -vec-report6 -o vec.out -xcore-avx2 -align array32byte


然后,我想在 VECTORLENGTH(n)之后添加 SIMD子句。
如果没有这样的子句或n = 2、4,则信息不会提供有关展开系数的信息

如果n = 8、16, vectorization support: unroll factor set to 2

我已经读过英特尔关于 vectorization support: unroll factor set to xxxx的文章,所以我想循环会展开为:

    DO IELEM = 1 , NELEM, 2
X(IKLE(IELEM)) = X(IKLE(IELEM)) + W(IELEM)
X(IKLE(IELEM+1)) = X(IKLE(IELEM+1)) + W(IELEM+1)
ENDDO


然后2 X进入向量寄存器,2 W进入另一个寄存器,进行加法运算。
但是VECTORLENGTH的值如何工作?也许我不太了解向量长度的含义。

而且由于我使用avx2指令,对于 DOUBLE PRECISION类型 X,可以达到的最大长度是多少?

这是SSE2,VL = 8的循环汇编的一部分,编译器告诉我展开系数为2。但是它使用4个寄存器而不是2个寄存器。

.loc    1  114  is_stmt 1
movslq main_vec_$IKLE.0.1(,%rdx,4), %rsi #114.9
..LN202:
movslq 4+main_vec_$IKLE.0.1(,%rdx,4), %rdi #114.9
..LN203:
movslq 8+main_vec_$IKLE.0.1(,%rdx,4), %r8 #114.9
..LN204:
movslq 12+main_vec_$IKLE.0.1(,%rdx,4), %r9 #114.9
..LN205:
movsd -8+main_vec_$X.0.1(,%rsi,8), %xmm0 #114.26
..LN206:
movslq 16+main_vec_$IKLE.0.1(,%rdx,4), %r10 #114.9
..LN207:
movhpd -8+main_vec_$X.0.1(,%rdi,8), %xmm0 #114.26
..LN208:
movslq 20+main_vec_$IKLE.0.1(,%rdx,4), %r11 #114.9
..LN209:
movsd -8+main_vec_$X.0.1(,%r8,8), %xmm1 #114.26
..LN210:
movslq 24+main_vec_$IKLE.0.1(,%rdx,4), %r14 #114.9
..LN211:
addpd main_vec_$W.0.1(,%rdx,8), %xmm0 #114.9
..LN212:
movhpd -8+main_vec_$X.0.1(,%r9,8), %xmm1 #114.26
..LN213:
..LN214:
movslq 28+main_vec_$IKLE.0.1(,%rdx,4), %r15 #114.9
..LN215:
movsd -8+main_vec_$X.0.1(,%r10,8), %xmm2 #114.26
..LN216:
addpd 16+main_vec_$W.0.1(,%rdx,8), %xmm1 #114.9
..LN217:
movhpd -8+main_vec_$X.0.1(,%r11,8), %xmm2 #114.26
..LN218:
..LN219:
movsd -8+main_vec_$X.0.1(,%r14,8), %xmm3 #114.26
..LN220:
addpd 32+main_vec_$W.0.1(,%rdx,8), %xmm2 #114.9
..LN221:
movhpd -8+main_vec_$X.0.1(,%r15,8), %xmm3 #114.26
..LN222:
..LN223:
addpd 48+main_vec_$W.0.1(,%rdx,8), %xmm3 #114.9
..LN224:
movsd %xmm0, -8+main_vec_$X.0.1(,%rsi,8) #114.9
..LN225:
.loc 1 113 is_stmt 1
addq $8, %rdx #113.7
..LN226:
.loc 1 114 is_stmt 1
psrldq $8, %xmm0 #114.9
..LN227:
.loc 1 113 is_stmt 1
cmpq $26000, %rdx #113.7
..LN228:
.loc 1 114 is_stmt 1
movsd %xmm0, -8+main_vec_$X.0.1(,%rdi,8) #114.9
..LN229:
movsd %xmm1, -8+main_vec_$X.0.1(,%r8,8) #114.9
..LN230:
psrldq $8, %xmm1 #114.9
..LN231:
movsd %xmm1, -8+main_vec_$X.0.1(,%r9,8) #114.9
..LN232:
movsd %xmm2, -8+main_vec_$X.0.1(,%r10,8) #114.9
..LN233:
psrldq $8, %xmm2 #114.9
..LN234:
movsd %xmm2, -8+main_vec_$X.0.1(,%r11,8) #114.9
..LN235:
movsd %xmm3, -8+main_vec_$X.0.1(,%r14,8) #114.9
..LN236:
psrldq $8, %xmm3 #114.9
..LN237:
movsd %xmm3, -8+main_vec_$X.0.1(,%r15,8) #114.9
..LN238:

最佳答案

1)向量长度N是循环“向量化”后可以并行执行的许多元素/迭代(通常通过将数组X的N个元素放入单个向量寄存器中,并通过向量指令对其进行整体处理)。为简化起见,将向量长度视为此公式给出的值:

Vector Length (abbreviated VL) = Vector Register Width / Sizeof (data type)


对于AVX2,向量寄存器宽度= 256位。 Sizeof(双精度)= 8字节= 64位。从而:

Vector Length (double FP, avx2) = 256 / 64 = 4


$ DIR SIMD VECTORLENGTH(N)基本上强制编译器使用指定的向量长度(并将数组X的N个元素放入单个向量寄存器中)。而已。

2)展开和向量化关系。为简化起见,将展开和矢量化视为通常不相关(有点“正交”)的优化技术。

如果您的循环展开了M倍(M可能是2、4,..),那么这并不一定意味着使用了向量寄存器,也并不意味着您的循环在任何意义上都是并行的。相反,它的意思是原始循环迭代的M个实例已被分组为单个迭代。并且在给定的新“展开” /“展开”迭代中,旧的迭代是一个接一个地依次执行的(因此您的猜测示例绝对正确)。

展开的目的通常是使循环更“微体系结构/内存友好”。更详细地讲:通过使循环迭代更“胖”,通常可以改善CPU资源压力与Memory / Cache资源压力之间的平衡,尤其是因为展开后通常可以更有效地重用寄存器中的某些数据。

3)展开+矢量化。编译器同时对某些循环进行矢量化(VL = N)和展开(按M)的情况并不少见。结果,优化循环中的迭代数比原始循环中的迭代数小NxM倍,但是并行处理的元素数(在给定的时间点同时)将仅为N。
因此,在您的示例中,如果将循环用VL = 4向量化,并展开2,则其伪代码可能类似于:

DO IELEM = 1 , NELEM, 8
[X(IKLE(IELEM)),X(IKLE(IELEM+2)), X(IKLE(IELEM+4)), X(IKLE(IELEM+6))] = ...
[X(IKLE(IELEM+1)),X(IKLE(IELEM+3)), X(IKLE(IELEM+5)), X(IKLE(IELEM+7))] = ...
ENDDO


,其中方括号“对应”向量寄存器的内容。

4)展开的矢量化:


对于迭代次数相对较少的循环(尤其是在C ++中)-可能会发生展开不理想的情况,因为它部分阻止了有效的矢量化(没有足够的迭代并行执行),并且(如您从我的人工示例中看到的)必须从内存中加载数据的方式。不同的编译器具有不同的启发式方法,可以相互平衡跳闸计数,VL和展开。这就是为什么当VL小于8时在您的情况下禁用展开功能的原因
可以使用“ Intel (Vectorization) Advisor”探索行数,展开和向量长度以及适当的自动建议(尤其是在使用新的Intel C ++或Fortran编译器的情况下)之间的运行时和编译时权衡:
enter image description here


5)附言第三维(我不太喜欢谈论)。

如果用户请求的vectorlength大于给定硬件上的可能Vector Vector长度(例如,对于双FP的avx2平台,请指定vectorlength(16)),或者当您混合使用不同类型时,编译器可以(或不能)开始使用“虚拟向量寄存器”,然后开始进行双/四泵。 M-pumping是一种展开,但仅针对单条指令(即,抽奖导致重复单条指令,而展开则导致重复整个循环体)。您可以尝试阅读有关最近的OpenMP书中有关m-pumping的信息,例如 one。因此,在某些情况下,您可能会遇到以下问题:a)向量化,b)展开和c)双重泵浦,但是这种情况并不常见,我会避免强制vectorlength> 2 * ISA_VectorLength。

关于fortran - fortran循环的simd向量长度和展开因子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32067818/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com