OpenMP计划中的低性能

时间:2010-12-22 18:11:52

标签: performance debugging parallel-processing openmp

我试图了解来自here的openmp代码。你可以看到下面的代码。

  1. 为了测量串口和omp版本之间的加速,差异,我使用time.h,你是否找到了这种方法?

  2. 该程序在4核机器上运行。我指定export OMP_NUM_THREADS="4"但是看不到大幅加速,通常我得到1.2 - 1.7。我在这个并行化中面临哪些问题?

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

  4. 代码(用于编译我使用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 个答案:

答案 0 :(得分:1)

上面的代码没有什么问题,但是你的加速将受到主循环c = a + b几乎没有工作的事实的限制 - 进行计算所需的时间(a单个添加)将由内存访问时间(2个加载和一个存储)控制,并且存在更多内存带宽争用,更多线程作用于阵列。

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

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(这里不是问题),一般OpenMP问题的scalasca,以及OpenSpeedShop也非常有用。