对于c中的循环优化

时间:2018-04-12 05:14:05

标签: c for-loop openmp

如何优化循环:

for (l = 1; l <= loop; l++) {
    for (i = 1; i < n; i++) {
        x[i] = z[i] * (y[i] - x[i - 1]);
    }
}

如何通过OpenMp

进行原始版本和优化版本的并行?

3 个答案:

答案 0 :(得分:3)

假设您要并行化内循环

for ( i = 1; i < n; ++i ) {
    x[i] = z[i] * ( y[i] - x[i - 1] );
}

我建议预先计算不依赖于前一循环的部分。这更容易并行化。

double preComps [n];
#pragma omp parallel for
for( i = 1; i < n ; ++i ) {
    preComps[i] = z[i] * y[i];
}

// this loop is difficult to parallelize because of the data dependency on what was computed in the previous loop
for( i = 1; i < n ; ++i ) {
    x[i] = preComps[i] - z[i] * x[i - 1];
}

答案 1 :(得分:1)

OUTER LOOP(假设没有别名,请参见下面的允许别名)

当您对外部循环控件变量l进行无引用时,您甚至不会引用相同的赋值术语在内循环中没有产生横向效应,运行内循环是幂等的,运行一次或多次没有任何好处,所以一个非常好的优化是完全消除它:),如下例所示:

pru.c

00001: #include <stdio.h>
00002: #include <stdlib.h>
00003: #define n 10
00004: #define loop 30


00005: void print(int x[], int y[], int z[])
00006: {
00007:      int i;
00008:      printf("%12s%12s%12s%12s\n","i", "x[]", "y[]", "z[]");
00009:      for(i = 0; i < n; i++)
00010:              printf("%12d%12d%12d%12d\n", i, x[i], y[i], z[i]);
00011: }
00012: int main()
00013: {
00014:      int x[n], y[n], z[n];
00015:      int i, l;
00016:      for(i = 0; i < n; i++) {
00017:              x[i] = rand();
00018:              y[i] = rand();
00019:              z[i] = rand();
00020:      }

打印开头

00021:      print(x, y, z);

接下来是发布的循环:

00022:      for (l = 1; l <= loop; l++) {
00023:              printf("iteration %d\n", l);

00024:         for (i = 1; i<n; i++) {
00025:              x[i] = z[i] * (y[i] - x[i - 1]);
00026:         }

并打印

00027:              print(x, y, z);

00028:      }

发布循环结束

00029: }

如您所见,循环传递之间的数组内容没有差异。接下来是一个程序运行来演示:

初始内容:

$ a.out
           i         x[]         y[]         z[]
           0       33613   564950497  1097816498
           1  1969887315   140734212   940422543
           2   202055087   768218108   770072198
           3  1866991770  1647128879    83392682
           4  1421485336   148486083   229615973
           5   127561358   735081006    33063457
           6  1646757679   287085223  1793088605
           7   802182690   382151770  1848710666
           8  1486775472   115658218   394986197
           9   661076908  1786703631   864107022

第一次迭代:

iteration 1
           i         x[]         y[]         z[]
           0       33613   564950497  1097816498
           1 -1607135687   140734212   940422543
           2  1213242898   768218108   770072198
           3 -1987622590  1647128879    83392682
           4 -1113079323   148486083   229615973
           5  -327431319   735081006    33063457
           6   407021958   287085223  1793088605
           7  1996444744   382151770  1848710666
           8   500660170   115658218   394986197
           9   -84727866  1786703631   864107022
iteration 2
           i         x[]         y[]         z[]
           0       33613   564950497  1097816498
           1 -1607135687   140734212   940422543
           2  1213242898   768218108   770072198
           3 -1987622590  1647128879    83392682
           4 -1113079323   148486083   229615973
           5  -327431319   735081006    33063457
           6   407021958   287085223  1793088605
           7  1996444744   382151770  1848710666
           8   500660170   115658218   394986197
           9   -84727866  1786703631   864107022
iteration 3
           i         x[]         y[]         z[]
           0       33613   564950497  1097816498
           1 -1607135687   140734212   940422543
           2  1213242898   768218108   770072198
           3 -1987622590  1647128879    83392682
           4 -1113079323   148486083   229615973
           5  -327431319   735081006    33063457
           6   407021958   287085223  1793088605
           7  1996444744   382151770  1848710666
           8   500660170   115658218   394986197
           9   -84727866  1786703631   864107022

...迭代重复直到

iteration 30
           i         x[]         y[]         z[]
           0       33613   564950497  1097816498
           1 -1607135687   140734212   940422543
           2  1213242898   768218108   770072198
           3 -1987622590  1647128879    83392682
           4 -1113079323   148486083   229615973
           5  -327431319   735081006    33063457
           6   407021958   287085223  1793088605
           7  1996444744   382151770  1848710666
           8   500660170   115658218   394986197
           9   -84727866  1786703631   864107022
$ _

INNER LOOP

如果你重新排序内部表达式,你也可以在内部循环中获得一些好处,如

x[0]
 \----.
      |
x[1] <+- y[1], z[1]
  \---.
      |
x[2] <+- y[2], z[2]
  .
  .
  .
x[n-1]<+- y[n-1],z[n-1]
   \--.
      |
x[n] <+- y[n], z[n]

如果您将表达式重新排列为x[i] = z[i]*y[i] - z[i]*x[i-1],则可以z[i]*y[i]的所有计算进行并行化,并在z[i]*x[i-1]的值尽快计算x[i-1]计算,在计算内循环时获得更多时间。

 thrd[0]   thrd[1]    thrd[2]      ... thrd[j]   ...  thrd[n]
============================================================
z[1]*x[0]  z[1]*y[1]     z[2]*y[2] ... z[j]*y[j] ... z[n-1]*y[n-1]
    |          |             |             |                |        
    \----------+-------.     |             |                |
           ,---'       |     |             |                |
           |           |     |             |                |
           V           V     |             |                |
x[1] = z[1]*y[1] - z[1]*x[0] |             |                |
  |                          |             |                |
  `--------------------.     |             |                |
                       |     |             |                |
           ,-----------+-----'             |                |
           |           |                   |                |
           V           V                   |                |
x[2] = z[2]*y[2] - z[2]*x[1]               |                |
  |                                        |                |
  `--------------------.                   |                |
           ,-----------+-------------------'                |
           |           |                                    |
          ...         ...                                   |
           V           V                                    |
x[j] = z[j]*y[j] - z[j]*x[j-1]                              |
...                                                         |                    
 |                                                          |
 `---------------------------.                              |
                             |                              |
               ,-------------+------------------------------'
               |             |
               V             V
x[n-1] = z[n-1]*y[n-1]-z[n-1]*x[n-2]

这可以通过两个线程池有效地计算。以前您有n-1个产品和n-1个减法产品,现在您有2*n个产品和n-1减法产品,并行计算,因此您最终无法节省成本(你得到两个线程,感谢KamiKaze向我展示了错误)

考虑到ALIASING

从上图可以看出,内环的计算仅取决于x[0]y[0...n-1]z[0...n-1],交叉值的唯一依赖性由表达式{ {1}}。如果您检查...如果我们将x[1] = f(x[0],z[1],y[1])xz别名,那么表达式会转换为yx[j] = f(x[j-1],x[j], y[j]),并且会生成值x[j] = f(x[j-1],z[j],x[j])通常取决于 x[j] 的先前值。在这些情况下(x[j]别名xy或两者都有),算法不是幂等的,并且外部循环不能被消除。如果仅zy别名,则表达式为z(或x[j] = f(x[j-1], y[j])),因此先前的值不存在依赖关系,并且算法是幂等的。

因此,总而言之,如果允许x[j] = f(x[j-1], z[j])向量与任何xy之间的别名,则无法消除外部循环,并且必须保留外部循环。在zy别名的情况下,算法继续是幂等的,并且外部循环不是必需的。

答案 2 :(得分:0)

外环只是噪音,它一直都是这样,正如路易斯在答案中所说的那样。因此,我们不必考虑这一点(或者可以大规模地将其平行化,但只做一次就足够了)....

内循环取决于前一个循环(x[i-1])。

当使用Multiply-Accumulate指令时,z * y将内循环更改为x[i] = preComps[i] - z[i] * x[i - 1];(由dvhh提出)的预计算可能会带来好处,但这是特定于实现的,我不会不知道这个的好处。

如果0中有z[],那么就有可能进行并行化。因为z[i] = 0 - &gt; x[i] = 0为您提供了在此时分割内循环的可能性

x[i+1]始终等于y[i+1] * z[i+1],这在任何时候都是已知的。为您提供另一个循环的入口点。

相关问题