关键区域的开销超过了环路并行化的加速

时间:2014-04-09 16:06:29

标签: c openmp

我正在尝试在函数

中并行化以下序列代码
    float arr[100];
    for ( int i = 0; i < 100; ++i) arr[i]=0;

    int i,j;
    for ( i = 0; i < 100; ++i) {
      float* pi = arr+i;
      int index[10];
      f(i, index); // f fills in the array index
      for (j = 0; j < 10; ++j) {
        float* pj = arr+index[j];
        if (pj > pi){
            float tmp = g(i,j); // some function g
            *pi += tmp;
            *pj += tmp;
        }
      }
    }

和类似的一个出现在另一个函数

    float arr[100];
    for ( int i = 0; i < 100; ++i) arr[i]=0;

    int i,j;
    for ( i = 0; i < 100; ++i) {
      float* pi = arr+i;
      int index[10];
      f(i, index); // f fills in the array index
      for (j = 0; j < 10; ++j) {
        float* pj = arr+index[j];
        if (pj > pi){    
            h(pi,i); // function h updates the memory pointed by pi, 
            // by adding to  to *pi something, which only depends on i but not on the values pointed by pi.
            h(pj,j); // 
        }
      }
    }

我的方式是:

    float arr[100];
    for ( int i = 0; i < 100; ++i) arr[i]=0;

    int i,j;
#pragma omp parallel for shared(arr) private(i,j) schedule(auto)
    for ( i = 0; i < 100; ++i) {
      float* pi = arr+i;
      int index[10];
      f(i, index);
      for (j = 0; j < 10; ++j) {
        float* pj = arr+index[j];
        if (pj > pi){
            float tmp = g(i,j);
            *pi += tmp;
            #pragma omp atomic update
            *pj += tmp;
        }
      }
    }

    float arr[100];
    for ( int i = 0; i < 100; ++i) arr[i]=0;

    int i,j;
#pragma omp parallel for shared(arr) private(i,j) schedule(auto)
    for ( i = 0; i < 100; ++i) {
      float* pi = arr+i;
      int index[10];
      f(i, index);
      for (j = 0; j < 10; ++j) {
        float* pj = arr+index[j];
        if (pj > pi){
           h(pi,i); 
           #pragma omp critical (pj)
           h(pj,j); // 
        }
      }
    }

我使用原子和关键指令,因为多个线程可以同时写入pj指向的内存。 (如果我是正确的,线程不会同时写入pi指向的内存。)

但是,添加原子和关键指令会使运行时间与串行代码的运行时间大致相同。

所以我想知道该怎么办?

1 个答案:

答案 0 :(得分:1)

并行化此代码的整个想法是有缺陷的。没有足够的工作来证明启动和同步线程的开销是合理的。

使用原子更新,同步本身的开销也不算太差,但关键部分破坏所有性能:一次只能有一个线程进入,并且典型的开销时间为同步大约为微秒(取决于等待的实现方式)。这比使用一个核心的工作要差得多。

如果您完全设置并行化(我不打算在此处使用“优化”一词)调用h()的循环,则应确保h()在线程安全中运行方式(可能使用原子操作),忘掉#pragma omp critical