嵌套循环的 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 矢量化的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 矩阵乘法嵌套循环

OpenMP 嵌套循环任务并行性,计数器未给出正确结果

openMP 嵌套并行 for 循环与内部并行 for

在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环

用于嵌套 for 循环的 OpenMP?

将 OpenMP 应用于 C++ 中的特定嵌套循环