如果连续快速运行,为什么这个简单程序的运行时间加倍?

时间:2018-02-04 03:07:49

标签: c arrays pointers caching openmp

我一直在介绍openmp示例和第一个多线程示例 - 对pi进行数值集成 - 我知道有关虚假共享的内容将会出现,所以实现了以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "omp.h"

#define STEPS 100000000.0
#define MAX_THREADS 4

void pi(double start, double end, double **sum);

int main(){
    double * sum[MAX_THREADS];

    omp_set_num_threads(MAX_THREADS);

    double inc;
    bool set_inc=false;
    double start=omp_get_wtime();
    #pragma omp parallel
    {
        int ID=omp_get_thread_num();
        #pragma omp critical
        if(!set_inc){
            int num_threads=omp_get_num_threads();
            printf("Using %d threads.\n", num_threads);
            inc=1.0/num_threads;
            set_inc=true;
        }

        pi(ID*inc, (ID+1)*inc, &sum[ID]);
    }
    double end=omp_get_wtime();
    double tot=0.0;
    for(int i=0; i<MAX_THREADS; i++){
        tot=tot+*sum[i];

    }
    tot=tot/STEPS;
    printf("The value of pi is: %.8f. Took %f secs.\n", tot, end-start);
    return 0;
}

void pi(double start, double end, double **sum_ptr){
    double *sum=(double *) calloc(1, sizeof(double));
    for(double i=start; i<end; i=i+1/STEPS){
        *sum=*sum+4.0/(1.0+i*i);
    }
    *sum_ptr=sum;
}

我的想法是,在使用calloc时,指针返回的概率是连续的,因此被拉入相同的缓存行几乎是不可能的(尽管我有点不确定为什么会有错误的共享无论如何,double是64位,我的缓存行也是8个字节,所以如果你能在那里启发我...)。 - 现在我意识到缓存行通常是64 bytes < / em>不是

有趣的是,在编译之后我快速连续运行了程序,这是我得到的一个简短的例子(肯定是推动箭头并在终端输入超过1次/ .5秒):

user@user-kubuntu:~/git/openmp-practice$ ./pi_mp.exe
Using 4 threads.
The value of pi is: 3.14159273. Took 0.104703 secs.
user@user-kubuntu:~/git/openmp-practice$ ./pi_mp.exe
Using 4 threads.
The value of pi is: 3.14159273. Took 0.196900 secs.

我认为可能发生了一些事情,因为我试图避免错误分享的方式,因为我仍然对记忆水平之间的完整事件一无所知,我将其归结为此。所以,我按照教程的规定方法使用“关键”部分,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "omp.h"

#define STEPS 100000000.0
#define MAX_THREADS 4

double pi(double start, double end);

int main(){
    double sum=0.0;

    omp_set_num_threads(MAX_THREADS);

    double inc;
    bool set_inc=false;
    double start=omp_get_wtime();
    #pragma omp parallel
    {
        int ID=omp_get_thread_num();
        #pragma omp critical
        if(!set_inc){
            int num_threads=omp_get_num_threads();
            printf("Using %d threads.\n", num_threads);
            inc=1.0/num_threads;
            set_inc=true;
        }

        double temp=pi(ID*inc, (ID+1)*inc);
        #pragma omp critical
        sum+=temp;
    }
    double end=omp_get_wtime();

    sum=sum/STEPS;
    printf("The value of pi is: %.8f. Took %f secs.\n", sum, end-start);
    return 0;
}

double pi(double start, double end){
    double sum=0.0;
    for(double i=start; i<end; i=i+1/STEPS){
        sum=sum+4.0/(1.0+i*i);
    }
    return sum;
}

运行时间加倍几乎相同。对此有何解释?它与低级内存有什么关系吗?你能回答我的中间问题吗?

非常感谢。

修改

编译器是Kubuntu 17.10上的gcc 7。使用的选项是-fopenmp -W -o(按此顺序)。

系统规格包括i5 6500 @ 3.2Ghz和16演出的DDR4 RAM(虽然我忘记了它的时钟速度)

正如有些人所说,如果连续两次运行超过两次,程序时间不会继续加倍。在初始加倍之后,它与我测试的连续运行次数大约相同(约.2秒)(5秒)。等待一两秒,运行时间返回到较小的数量。 但是,当运行不是连续手动运行而是在一个命令行中运行时,例如./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;我得到:

The value of pi is: 3.14159273. Took 0.100528 secs.
Using 4 threads.
The value of pi is: 3.14159273. Took 0.097707 secs.
Using 4 threads.
The value of pi is: 3.14159273. Took 0.098078 secs.
...

添加gcc优化选项(-O3)对任何结果都没有变化。

0 个答案:

没有答案