2

对于图像处理,我有一个 openmp 并行循环贯穿图像的每一行。在循环内我使用 SSE 内在函数:

#pragma omp parallel for
for( int y=0; y<=img->height; y++ ) 
{
    [SSE Code]
}

从 SSE 切换到 FPU 代码时,我需要使用 _mm_empty。我的理解是openmp使用的每个cpu都需要执行_mm_empty。

我当前的代码显然是错误的:

#pragma omp parallel for
for( int y=0; y<=img->height; y++ ) 
{
    [SSE Code]
}

_mm_empty();

只有一个 CPU 会重新初始化其 FPU。

到目前为止,我想出的最佳解决方案有性能损失:

#pragma omp parallel for
for( int y=0; y<=img->height; y++ ) 
{
    [SSE Code]
    _mm_empty();
}

这将为每个循环迭代调用 _mm_empty。我期待 OpenMP 创建一个线程池,其中包含与可用 CPU 一样多的线程,并在它们之间分配工作。例如,具有 720 行和 4 个 CPU 的图像,这将导致 _mm_empty 被执行 720 次,而不是所需的 4 次。

OpenMP 中是否有任何定义清理代码的概念,由每个线程执行?就像是

#pragma omp parallel for on thread exit( _mm_empty(); )
for( int y=0; y<=img->height; y++ ) 
{
    [SSE Code]
}

或者有没有办法用其他 omp 概念来表达这一点?

4

1 回答 1

2

如果只是在每个线程中执行一条指令,那么标准omp parallel编译指示应该这样做:

#pragma omp parallel for
for( int y=0; y<=img->height; y++ ) 
{
    [SSE Code]
}

#pragma omp parallel
_mm_empty();

或者结合在一起

#pragma omp parallel
{
    #pragma omp for
    for( int y=0; y<=img->height; y++ ) 
    {
        [SSE Code]
    }
    #pragma omp barrier    //maybe, maybe not?
    _mm_empty();
}

但是您面临的实际问题是,您不能确定这是否真的_mm_empty在前一个循环使用的每个核心上执行。您只能保证在其循环之后在每个线程中调用它(并且在所有线程完成其循环之后使用屏障),但是 OpenMP 运行时(或操作系统)可以自由地在任何地方以及无论何时发生重新调度时调度线程。但是一个明智的运行时/操作系统确实应该关心线程被分配给特定的内核并留在那里,也许你甚至可以通过一些 OpenMP 或操作系统功能以某种方式调整它。

但你知道吗,你可能根本不需要这种_mm_empty疯狂。请记住,仅在使用MMX_mm_empty指令时才需要,这些指令是SSE的前身(只有 64 位而不是 128 位)并使用与x87 FPU相同的寄存器。但是SSE带来了自己的一组寄存器以及自己的状态和控制标志。所以SSE不会以任何方式干扰“经典”FPU,也不需要任何同步。因此,如果您使用的只是SSE操作而不是MMX(即您只使用过类型而从未使用过类型),那么请忘记.__m128(i)__m64_mm_empty

于 2013-06-06T15:27:47.900 回答