OpenMP适合初学者

时间:2015-03-01 19:38:21

标签: c multithreading parallel-processing openmp

我刚开始使用openMP;我写了一个小C代码,以检查我研究的内容是否正确。但是我发现了一些麻烦;这是 main.c 代码

#include "stdio.h"
#include "stdlib.h"
#include "omp.h"
#include "time.h"

int main(){

float msec_kernel;
const int N = 1000000;
int i, a[N];

clock_t start = clock(), diff;
#pragma omp parallel for private(i)
for (i = 1; i <= N; i++){
    a[i] = 2 * i;
}
diff = clock() - start;
msec_kernel = diff * 1000 / CLOCKS_PER_SEC; 
printf("Kernel Time: %e s\n",msec_kernel*1e-03);
printf("a[N] = %d\n",a[N]);
return 0;
}

我的目标是看看PC使用1和2个CPU进行此类操作需要多长时间;为了编译程序,我在终端中键入以下行:

gcc -fopenmp main.c -o main

然后我选择像这样的CPU数量:

export OMP_NUM_THREADS=N

其中N为1或2;但是我没有得到正确的执行时间;我的结果实际上是:

Kernel Time: 5.000000e-03 s
a[N] = 2000000

Kernel Time: 6.000000e-03 s
a[N] = 2000000

两者都对应于N = 1和N = 2。正如你所看到的,当我使用2个CPU时,它比仅使用一个CPU需要更多的时间!我究竟做错了什么?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

首先,使用多个核心并不意味着,您将获得更好的性能。

OpenMP必须管理您的核心之间的数据分配,这也需要时间。特别是对于非常基本的操作,例如你只做一次乘法,顺序(单核)程序的性能会更好。

其次,通过遍历数组中的每个元素只执行一次而不执行任何其他操作,您不使用缓存内存,而且肯定不会使用cpu之间的共享缓存。

因此,您应该开始阅读有关通用算法性能的一些内容。在我看来,使用共享缓存来利用多个核心的本质。 今天的计算机已进入一个阶段,CPU比内存分配,读取或写入快得多。这意味着当使用多个内核时,如果您使用共享缓存之类的东西,那么您将获益,因为数据分发,线程初始化和管理它们也将使用时间。要真正看到性能speedup(请参阅链接,并行计算中的基本术语),您应该编写一个算法,该算法在计算时非常重视内存;这与locality(另一个重要术语)有关。

因此,如果您希望通过使用多核来体验大的性能提升,则可以在大矩阵(例如10'000 * 10'000)上对矩阵 - 矩阵乘法进行测试。并绘制一些图表,其中输入大小(矩阵大小)为时间,矩阵大小为gflops,并将多核与顺序版本进行比较。

还要熟悉复杂性分析(Big O表示法)。 矩阵 - 矩阵乘法的局部性为O(n)。

希望这会有所帮助: - )

我建议直接在#pragma line #pragma omp parallel for num_threads(2)或使用omp_set_num_threads函数omp_set_num_threads(2);

设置代码中的核心/线程数量

此外,在进行时间/性能分析时,始终多次运行程序然后取所有运行时的平均值或类似的东西非常重要。仅运行一次相应的程序不会给您有意义的使用时间读数。始终连续多次呼叫。不要忘记也交替使用数据质量。

我建议编写一个test.c文件,它将你的实际程序函数放在一个循环中,然后计算每次执行该函数的时间:

int executiontimes = 20;
clock_t initial_time = clock();
for(int i = 0; i < executiontimes; i++){
    function_multiplication(values);    
}
clock_t final_time = clock();
clock_t passed_time = final_time - initial_time;
clock_t time_per_exec = passed_time / executiontimes;

改进这个测试算法,为你的值添加一些rand()等。用srand()等种子。如果你对这个问题或我的回答有更多的问题,请留下评论,我会尝试进一步解释添加更多解释。

答案 1 :(得分:0)

函数clock()返回经过的CPU时间,其中包括来自所有核心的滴答。由于使用多个线程会产生一些开销,因此当您对所有线程的执行时间求和时,总CPU时间将始终长于串行时间。

如果您想要实时(挂钟时间),请尝试使用omp_get_wtime()中定义的OMP运行时库函数omp.h。它是跨平台便携式的,应该是进行墙壁定时的首选方式。

您还可以使用time.h中定义的POSIX函数:

struct timespec start, stop;
clock_gettime(CLOCK_REALTIME, &start);
// action
clock_gettime(CLOCK_REALTIME, &stop);
double elapsed_time = (stop.tv_sec - start.tv_sec) + 
                      1e-9 * (stop.tv_nsec - start.tv_nsec);