1

在英特尔 MIC(至强融核)卡上的卸载调用之后,我正在尝试并行化我的 C/OpenMP 代码的“for 循环”。我正在使用“#pragma omp parallel for”,当我使用整数变量作为“循环控制变量”时它编译得很好。在我的代码中,我使用浮点数组作为“循环控制变量”,然后出现错误“并行循环条件不测试循环控制变量”。

没有错误的代码:

#define MAX_DIMENSIONS  10

unsigned long long  i,y=0;

#pragma offload target(mic) in(i,y)
{
    #pragma omp parallel for
    for(i=0;i<10;i++)
        /* code here */  
}

有错误的代码:

#define MAX_DIMENSIONS  10

float   x[MAX_DIMENSIONS];
unsigned long long  i,y=0;

#pragma offload target(mic) in(x[MAX_DIMENSIONS],i,y)
{
    #pragma omp parallel for
    for(x[0]=0.000000; x[0]<10.000000; x[0]+=1.000000)
        /* code here */
}

有什么方法可以将该浮点数组表示法保留在“for 循环”中,以便使用 OpenMP 成功进行并行化?

4

2 回答 2

4

OpenMP 要求循环变量为整数类型:

http://www.openmp.org/wp-content/uploads/openmp-4.5.pdf#page=68

循环结构的语法如下:

#pragma omp for  ...
 for-loops

...

具体来说,所有相关的 for 循环都必须具有规范的循环形式(参见第 53 页的第 2.6 节)。

3 每个关联循环的迭代计数在进入最外层循环之前计算。如果任何关联循环的执行更改了用于计算任何迭代计数的任何值,则行为未指定。

6 用于计算折叠循环的迭代计数的整数类型(或类型,对于 Fortran)是实现定义的。

您不能在 openmp 循环构造中使用浮动类型的变量。您的第一个循环具有i正确的整数,第二个循环具有不正确的float类型变量。规范循环形式在“2.6 规范循环形式” - http://www.openmp.org/wp-content/uploads/openmp-4.5.pdf#page=62中定义为

for (init-expr; test-expr; incr-expr) structured-block
...
var - One of the following:
* A variable of a signed or unsigned integer type.
* For C++, a variable of a random access iterator type.
* For C, a variable of a pointer type

incr-expr One of the following:
 ...
* var += incr

 incr A loop invariant integer expression

并且您的第二个循环没有规范形式并且不能并行。

#pragma omp parallel for
for(x[0]=0.000000; x[0]<10.000000; x[0]+=1.000000)

编译器很难使用 var 和 incr 的浮点值提前获取循环迭代计数:一些十进制常量不能以浮点格式精确表示(例如,浮点中的 0.2 是 0f3FC999999999999A;和 0.1 + 0.2在多种语言中是 0.30000000000000004,请查看https://0.30000000000000004.com/)。

您可以尝试整数数组或longs 或long longs:

#define MAX_DIMENSIONS  10

long long  x[MAX_DIMENSIONS];
unsigned int i,y=0;

#pragma offload target(mic) in(x[MAX_DIMENSIONS],i,y)
{
    #pragma omp parallel for
    for(x[0]=0; x[0] < 10; x[0] += 1)
        /* code here */
}

或者您可以尝试在循环之前估计浮点范围的正确循环计数,然后在并行循环中使用整数迭代器作为 var 和 incr(确保进行正确的舍入)。

于 2017-09-19T17:49:59.690 回答
2

您可以像这样手动实现工作共享

#pragma omp parallel
{
    float a = 0., b = 10.;
    float step = 1.;
    int N = (b-a)/step;
    int ithread = omp_get_thread_num();
    int nthreads = omp_get_num_threads();
    float t0 = (ithread+0)*N/nthreads + a;
    float t1 = (ithread+1)*N/nthreads + a;
    for(float x=t0; x<t1; x += step) {
      //code
    }
}

这相当于

#pragma omp parallel for 
for(float x=a; x<b; x += step)

如果omp for构造支持浮点迭代器。对于其他时间表(例如动态),您必须以不同的方式实施它们。请注意,并行代码和顺序代码可能不会给出相同的结果,例如,如果(b-a)/step有小数部分(但(10.-0)/1. = 10.没关系)。因此,为了安全起见,最好将代码更改为使用整数迭代器。

于 2017-09-21T09:49:40.143 回答