首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >英特尔自动矢量法旅行计数解释?

英特尔自动矢量法旅行计数解释?
EN

Stack Overflow用户
提问于 2015-10-23 13:09:58
回答 2查看 740关注 0票数 4

我已经做了相当多的线程级和进程级并行化,现在我尝试使用Intel C++编译器进行指令级并行处理,这是一个相当大的挑战。

在对循环进行自动矢量化和对编译器日志进行分析时,我发现了一些“循环最大行程计数的估计”,但我不太清楚。

示例:

代码语言:javascript
运行
复制
double a[100],x[100],y[100]
...
for (i=0; i< 100; i++) {
   a[i] = x[i] + y[i];
}

这个循环输出12次行程的最大行程数的估计值。我在某个地方读到,矢量化过程每次行程总共可以处理8个元素,只要每个周期的处理成本小于6u操作,据我所知,这个示例循环的成本为1存储、2读和1算术操作。

所以在理论上,我的旅行次数应该是100/8 = 12.5次,因此,13次。

这是编译器做的集合吗?或者,在后台是否还有其他优化,允许流程少于13次旅行?

还有一个问题,我的每个周期的6u运算正确吗?是否有不适用的情况?

提前感谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-26 11:11:55

与其纠缠于Intel是如何实现每个循环的,不如让我们尝试回答您关于指令级并行性的问题。

您的操作受到读和写的限制,因此在确定周期数时可以忽略算法。以下是Core2通过布罗德韦尔所能做的事情:

代码语言:javascript
运行
复制
Core2:   two 16 byte reads one 16 byte write per 2 clock cycles     -> 24 bytes/clock cycle
SB/IB:   two 32 byte reads and one 32 byte write per 2 clock cycles -> 48 bytes/clock cycle
HSW/BDW: two 32 byte reads and one 32 byte write per clock cycle    -> 96 bytes/clock cycle

正在读取和写入的字节总数为sizeof(double)*100*3=2400。因此,快速估计所需时间是

代码语言:javascript
运行
复制
Core2:   2400/24 = 100 clock cycles
SB/IB:   2400/48 =  50 clock cycles
HSW/BDW: 2400/96 =  25 clock cycles

现在的问题是如何在全带宽范围内实现这一点。

对于Core2,通过常春藤桥,其中的一个负荷可以与一个额外的成本,一个微型熔断微操作。另一个负载需要一个微操作,负载需要一个微操作。如果您想在每次迭代时都这样做,那么您可以使用need to decrease a pointer and do a conditional jump as well。由于Nehalem,这些可以宏融合,因此每次迭代的微融合/宏融合操作的总数是:

代码语言:javascript
运行
复制
                            Core2          Nehalem through Broadwell
vector add + load               1          1
vector load                     1          1
vector store                    1          1
scalar add                      1          ½
conditional jump                1          ½  
--------------------------------------------
total                           5          4

对于通过常春藤桥的Core2来说,要么两个负载都需要相同的端口,要么负载和存储需要相同的端口。这需要两个时钟周期。对于Haswell/Broadwell来说,每一个时钟周期都有可能发生这种情况。然而,due to limitations on port 7 only statically allocated arrays can achieve this使用绝对-32位地址+偏移地址(which incidentally is not possible on OSX).因此,对于Haswell/Broadwell,如果没有静态分配数组,则要么必须展开循环来执行每个时钟周期的操作,要么每次迭代需要1.5个时钟周期。以下是每个处理器每次迭代的时钟周期摘要:

代码语言:javascript
运行
复制
Core2:   5 fused micro-ops/every two clock cycles
SB/IB:   4 fused micro-ops/every two clock cycles
HSW/BDW: 4 fused mirco-ops/every clock cycle for statically allocated array
HSW/BDW: 4 fused mirco-ops/every 1.5 clock cycles for non-statically allocated arrays

如果使用堆栈分配数组,则可能可以安全地读取缓冲区的末尾。否则,您应该将数组放置到SIMD宽度。然后循环的迭代次数是:

代码语言:javascript
运行
复制
SSE2: (100+1)/2 = 51
AVX:  (100+3)/4 = 26

在我的经验中,Intel编译器展开了两次,这样迭代次数就减少了一半。展开两次的迭代次数是

代码语言:javascript
运行
复制
SSE2: (100+3)/4 = 26
AVX:  (100+7)/8 = 13

最后,就时钟周期而言

代码语言:javascript
运行
复制
Core2:     51*2   = 102 clock cycles
SB/IB:     26*2   =  51 clock cycles
HSW/BDW:   26*1.5 =  39 clock cycles for non-statically allocated arrays no-unroll
HSW/BDW:   26*1   =  26 clock cycles for statically allocated arrays no-unroll
HSW/BDW:   26*1   =  26 clock cycles with full unrolling
票数 3
EN

Stack Overflow用户

发布于 2015-10-24 02:51:34

6-uops听起来像是一个正确的估计,如果不展开。英特尔编译器通常在展开自动矢量化循环方面做得很好。在这种特殊情况下,即使是完全展开也可能是有意义的。

不确定如何一次获得8个元素,因为即使使用AVX,也只能在一个256位ymm寄存器中获得4个双精度值。

关于行程的统计。即使一次可以执行8个元素,它也将是12个,而不是13个,因为最后几个元素(一次不能处理8个)将使用标量代码完成。

因此,从编译器的角度来看,它将如下所示:

代码语言:javascript
运行
复制
int i=0;
for(; i<(100 & ~7); i+=8) // 12 iterations
    // Do vector code

for(;i<100; ++i)
    // Process loop remainder using scalar code
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33303141

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档