一个OpenMP程序的性能低下

3

我正在尝试理解来自这里的一个OpenMP代码。下面是代码:

  1. 为了测量加速比,也就是串行版本与OpenMP版本之间的差异,我使用了time.h。你认为这个方法正确吗?

  2. 该程序在4核机器上运行。我指定export OMP_NUM_THREADS="4",但没有看到明显的加速效果,通常只有1.2-1.7倍。我在并行化中遇到了哪些问题?

  3. 我可以使用哪些调试/性能工具来查看性能损失?

代码(编译时使用xlc_r -qsmp=omp omp_workshare1.c -o omp_workshare1.exe

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#define CHUNKSIZE   1000000
#define N       100000000

int main (int argc, char *argv[]) 
{
    int nthreads, tid, i, chunk;
    float a[N], b[N], c[N];
    unsigned long elapsed;
    unsigned long elapsed_serial;
    unsigned long elapsed_omp;
    struct timeval start;
    struct timeval stop;


    chunk = CHUNKSIZE;

    // =================    SERIAL     start =======================
    /* Some initializations */
    for (i=0; i < N; i++)
        a[i] = b[i] = i * 1.0;
    gettimeofday(&start,NULL); 
    for (i=0; i<N; i++)
    {
        c[i] = a[i] + b[i];
        //printf("Thread %d: c[%d]= %f\n",tid,i,c[i]);
    }
    gettimeofday(&stop,NULL);
    elapsed = 1000000 * (stop.tv_sec - start.tv_sec);
    elapsed += stop.tv_usec - start.tv_usec;
    elapsed_serial = elapsed ;
    printf ("   \n Time SEQ= %lu microsecs\n", elapsed_serial);
    // =================    SERIAL     end =======================


    // =================    OMP    start =======================
    /* Some initializations */
    for (i=0; i < N; i++)
        a[i] = b[i] = i * 1.0;
    gettimeofday(&start,NULL); 
#pragma omp parallel shared(a,b,c,nthreads,chunk) private(i,tid)
    {
        tid = omp_get_thread_num();
        if (tid == 0)
        {
            nthreads = omp_get_num_threads();
            printf("Number of threads = %d\n", nthreads);
        }
        //printf("Thread %d starting...\n",tid);

#pragma omp for schedule(static,chunk)
        for (i=0; i<N; i++)
        {
            c[i] = a[i] + b[i];
            //printf("Thread %d: c[%d]= %f\n",tid,i,c[i]);
        }

    }  /* end of parallel section */
    gettimeofday(&stop,NULL);
    elapsed = 1000000 * (stop.tv_sec - start.tv_sec);
    elapsed += stop.tv_usec - start.tv_usec;
    elapsed_omp = elapsed ;
    printf ("   \n Time OMP= %lu microsecs\n", elapsed_omp);
    // =================    OMP    end =======================
    printf ("   \n speedup= %f \n\n", ((float) elapsed_serial) / ((float) elapsed_omp)) ;

}

你可能还想指定操作系统和编译器,以帮助其他人回答问题1和问题3。 - Chris O
1个回答

1

以上的代码没有什么真正的问题,但你的加速将受到主循环c=a+b工作量非常少的限制——进行计算(单个加法)所需的时间将被内存访问时间(2次加载和1次存储)支配,并且有更多的线程在数组上操作会导致对内存带宽的争用。

我们可以通过使循环内部的工作更加计算密集来测试这一点:

c[i] = exp(sin(a[i])) + exp(cos(b[i]));

然后我们得到

$ ./apb

 Time SEQ= 17678571 microsecs
Number of threads = 4

 Time OMP= 4703485 microsecs

 speedup= 3.758611 

显然,这更接近于人们期望的4倍加速。

更新:哦,至于其他问题——gettimeofday()可能适用于计时,在使用xlc的系统上——这是AIX吗?在这种情况下,peekperf是一个很好的整体性能工具,并且硬件性能监视器将使您可以访问内存访问时间。在x86平台上,用于线程代码性能监视的免费工具包括cachegrind / valgrind用于缓存性能调试(不是此处的问题),scalasca用于一般OpenMP问题,而OpenSpeedShop也非常有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接