OpenMP 手工还原指令
OpenMP Handmade reduction directive
我正在研究阶乘函数。我必须使用 OpenMP 编写其并行版本。
double sequentialFactorial(const int N) {
double result = 1;
for(int i = 1; i <= N; i++) {
result *= i;
}
return result;
}
众所周知,该算法可以使用约简技术有效地并行化。
我知道存在reduction
条款(标准§§2.15.3.6(。
double parallelAutomaticFactorial(const int N) {
double result = 1;
#pragma omp parallel for reduction(*:result)
for (int i=1; i <= N; i++)
result *= i;
return result;
}
但是,我想尝试实现"手工制作"的还原技术。
double parallelHandmadeFactorial(const int N) {
// maximum number of threads
const int N_THREADS = omp_get_max_threads();
// table of partial results
double* partial = new double[N_THREADS];
for(int i = 0; i < N_THREADS; i++) {
partial[i] = 1;
}
// reduction tecnique
#pragma omp parallel for
for(int i = 1; i <= N; i++) {
int thread_index = omp_get_thread_num();
partial[thread_index] *= i;
}
// fold results
double result = 1;
for(int i = 0; i < N_THREADS; i++) {
result *= partial[i];
}
delete partial;
return result;
}
我希望最后两个片段的性能非常相似,并且比第一个更好。但是,平均性能为:
Sequential Factorial 3500 ms
Parallel Handmade Factorial 6100 ms
Parallel Automatic Factorial 600 ms
我错过了什么吗?
多亏了 @Gilles 和 @P.W,这段代码可以按预期工作
double parallelNoWaitFactorial(const int N) {
double result = 1;
#pragma omp parallel
{
double my_local_result = 1;
// removing nowait does not change the performance
#pragma omp for nowait
for(int i = 1; i <= N; i++)
my_local_result *= i;
#pragma omp atomic
result *= my_local_result;
}
return result;
}
如果数组元素碰巧共享缓存行,则会导致错误共享,从而进一步导致性能下降。
要避免这种情况,请执行以下操作:
- 使用私有变量
double partial
而不是double
数组partial
. - 使用每个线程的
partial
结果计算关键区域中的最终result
- 此最终
result
应为非并行区域专用的变量。
关键区域将如下所示:
#pragma omp critical
result *= partial;
相关文章:
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- C++:对不存在的命名空间使用命名空间指令
- 函数名是c中该函数的第一条指令的地址吗
- 错误:无效的预处理指令 #i 的意思是 #if?
- 组装指令中乘法的下部和上部是什么
- OpenMP 与有序和关键指令并行
- C++中的移动分配出现问题.非法指令: 4.
- 嵌套命名空间的"using"指令,但需要命名内部命名空间
- C++CMake编译指令与
- 使用宏扩展的泛型:为什么指令缓存使用不当?
- 如何在 c++ 中确定一条指令(以字节为单位)在哪里结束,另一条指令从哪里开始?
- AVX 指令中寄存器和指针之间的客观差异
- while 循环 c++ 中的非法指令
- 如何在编译时定义C++预处理器指令的值?
- 为什么 g++ 使用 movabs 和一个奇怪的常数来简单还原?
- 存储指令是否会阻止缓存未命中的后续指令?
- 保证编译器指令在C++中重新排序
- VS2008中的AVX-512指令库
- OpenMP 手工还原指令