嵌套循环的 OpenMP SIMD 矢量化
Posted
技术标签:
【中文标题】嵌套循环的 OpenMP SIMD 矢量化【英文标题】:OpenMP SIMD vectorization of nested loop 【发布时间】:2016-03-20 07:18:19 【问题描述】:我正在尝试使用 OpenMP 4.0 的 simd
功能对嵌套循环进行矢量化,但恐怕我做错了。我的循环如下所示:
do iy = iyfirst, iylast
do ix = ixfirst, ixlast
!$omp simd
do iz = izfirst, izlast
dudx(iz,ix,iy) = ax(1)*( u(iz,ix,iy) - u(iz,ix-1,iy) )
do ishift = 2, ophalf
dudx(iz,ix,iy) = dudx(iz,ix,iy) + ax(ishift)*( u(iz,ix+ishift-1,iy) - u(iz,ix-ishift,iy) )
enddo
dudx(iz,ix,iy) = dudx(iz,ix,iy)*buoy_x(iz,ix,iy)
enddo
!$omp end simd
enddo
enddo
请注意,ophalf
是一个小整数,通常为 2 或 4,因此矢量化 iz
循环而不是最内层循环是有意义的。
我的问题是:我必须将ishift
标记为私有变量吗?
在标准 OpenMP parallel do
循环中,您当然需要 private(ishift)
以确保其他线程不会踩到彼此的数据。然而,当我将第一行改写为 !$omp simd private(ishift)
时,我得到了 ifort 编译错误:
错误 #8592:在 SIMD 区域内,不得在 PRIVATE SIMD 子句中指定 DO 循环控制变量。 [换档]
在网上查找,我找不到任何成功解决此问题的方法。在我看来,ishift
应该是私有的,但编译器不允许这样做。内部循环变量是否自动强制为私有?
后续问题:稍后,当我在iy
循环周围添加omp parallel do
时,我应该在omp parallel do
指令、omp simd
指令中包含private(ishift)
子句还是两者都包含?
感谢您的澄清。
【问题讨论】:
针对常见情况展开专门化的循环。 简单的omp simd
构造不是多线程的,它们是不同的向量化的。您保留循环的主体,但将标量指令替换为向量指令。如果您尝试自己手动编写此矢量化版本,您会立即明白为什么将ishift
设为私有毫无意义。
谢谢@Gilles。我已经知道你在说什么,但强迫自己试着写出来真的让我更好地理解它,并使你的观点非常明显。你是对的 - ishift
变量不应设为私有。此外,我想不出应该将循环迭代器设为私有的情况,因此 ifort 错误对我来说似乎是合理的。干杯。
我明白我一开始的问题是错的。我以为你在iy
循环周围有omp do private(ishift)
。在这种情况下,私人应该不是问题。
【参考方案1】:
涉及 SIMD 的私有子句本质上意味着 ishift 的值对于 SIMD 寄存器中的每个 SIMD 通道都是私有的。当我们对最内层循环进行矢量化时,这是正确的,因为 ishift 是循环感应变量。但是当你进行外循环向量化时,每个 SIMD 通道的 iz 循环索引值都会不同,但给定循环索引 iz,ishift 的值仍然可以从 2 到 ophalf 不等。因此它不符合 SIMD 上下文中的私有子句的条件。
当涉及到多个线程时,您需要 ishift 的副本,因此一个线程递增此变量不会使其他线程跳过该迭代。因此,私有子句对于 omp 并行执行上下文中的 ishift 是有意义的。如果内部循环完全展开并针对循环索引为 iz 的循环进行矢量化,那么检查底层代码生成将会很有趣。
【讨论】:
以上是关于嵌套循环的 OpenMP SIMD 矢量化的主要内容,如果未能解决你的问题,请参考以下文章