我是openmp的新手,正在尝试理解它的结构。
这是我写的一段简单的代码。(数字的平方)..
#include <omp.h>
#include <stdio.h>
#define SIZE 20000
#define NUM_THREADS 50
int main(){
int id;
int output[SIZE];
omp_set_num_threads(NUM_THREADS);
double start = omp_get_wtime();
#pragma omp parallel for
//{
//id = omp_get_thread_num();
for (int i=0; i<SIZE;i++){
id = omp_get_thread_num();
//printf("current thread :%d of %d threads\n", id, omp_get_num_threads());
output[i] = i*i;
}
//}
double end = omp_get_wtime();
printf("time elapsed: %f for %d threads\n", end-start, NUM_THREADS);
}
现在,改变线程的数量应该会减少时间。但实际上是在增加时间吗?我做错了什么?
发布于 2015-08-26 01:26:24
这很可能是因为您选择了要检查的问题。让我们来看看你的并行循环:
#pragma omp parallel for
for (int i=0; i<SIZE;i++){
id = omp_get_thread_num();
output[i] = i*i;
}
您指定了50个线程,并声明您有16个核心。
串行情况会忽略OMP指令,并可以执行积极的循环优化。每个元素的i
都是i*i
,这是一个简单的乘法,它只依赖于循环索引。id
是可以完全优化的。这可能是完全矢量化的,如果你的处理器是现代的,它可能可以在一条指令(单指令多数据)中进行4次乘法,这对size=2000
来说意味着500次单指令多数据乘法(没有数据获取开销和高速缓存友好的存储)。这将是非常快的。
或者,让我们看看并行版本。您正在初始化50个线程--开销很大!您引入了许多上下文切换,因为即使您拥有处理器亲和性,您也已经超额订阅了您的核心。50个线程中的每一个都将运行循环的40次迭代。如果幸运的话,编译器稍微展开了一下循环,这样它就可以进行SIMD乘法的10次迭代。乘法,无论SIMD或非SIMD,仍然会很快。你最终得到的是相同数量的实际工作,所以每个处理器有1/16的工作,但是创建和销毁50个线程的开销产生了比并行增益更多的工作。这是一个不能从并行化中获益的很好的例子。
你要做的第一件事就是把你的线程数量限制在你的实际内核上。通过在执行时间中添加不必要的上下文切换,您不会获得任何好处。比核心更多的线程通常不会让它运行得更快。
你想做的第二件事是在你的循环中做一些更复杂的事情,并且做很多次(谷歌的例子,有很多)。在构建工作循环时,您还需要考虑缓存性能,因为构造不佳的循环不会很好地加速。
当您将工作更改为比线程开销更复杂、令人难堪的并行和出色的缓存性能时,您可以开始看到OpenMP的真正好处。你要做的最后一件事是对你的循环从串行到16个线程进行基准测试。例如:
https://stackoverflow.com/questions/32163841
复制相似问题