我正在编写一个应该在串行和并行版本中运行的程序。一旦我真正做到它应该做的事情,我就开始尝试将它与OpenMP并行化(强制性)。
问题是我无法找到何时使用#pragma的文档或参考资料。所以我在猜测和测试时尽我所能。但是嵌套循环的测试并不顺利。
如何并行化一系列嵌套循环:
for(int i = 0; i < 3; ++i){
for(int j = 0; j < HEIGHT; ++j){
for(int k = 0; k < WIDTH; ++k){
switch(i){
case 0:
matrix[j][k].a = matrix[j][k] * someValue1;
break;
case 1:
matrix[j][k].b = matrix[j][k] * someValue2;
break;
case 2:
matrix[j][k].c = matrix[j][k] * someValue3;
break;
}
}
}
}
我知道OpenMP并不总是适用于嵌套循环,但欢迎任何帮助。
[UPDATE]:
到目前为止,我已尝试展开循环。它提升了性能,但我在这里添加了不必要的开销吗?我在重复使用线程吗?我尝试获取每个中使用的线程的ID,但没有做到正确。
#pragma omp parallel
{
#pragma omp for collapse(2)
for (int j = 0; j < HEIGHT; ++j) {
for (int k = 0; k < WIDTH; ++k) {
//my previous code here
}
}
#pragma omp for collapse(2)
for (int j = 0; j < HEIGHT; ++j) {
for (int k = 0; k < WIDTH; ++k) {
//my previous code here
}
}
#pragma omp for collapse(2)
for (int j = 0; j < HEIGHT; ++j) {
for (int k = 0; k < WIDTH; ++k) {
//my previous code here
}
}
}
[更新2]
除了展开循环外,我还尝试了并行化外循环(性能提升比展开最差)并折叠两个内循环(与展开相比,性能提升或多或少)。这是我得到的时间。
您认为最安全的选择是什么?我的意思是,对于大多数系统而言,这应该是最好的,而不仅仅是我的电脑?
答案 0 :(得分:1)
您可能希望并行化此示例for simd
,以便编译器可以向量化collapse
循环,因为您只在表达式{{1}中使用j
和k
因为矩阵的任何其他元素都没有依赖关系。如果没有任何内容修改matrix[j][k]
等,则它们应为somevalue1
。为你的循环计时,确保那些确实能提高你的速度。
答案 1 :(得分:1)
OpenMP的问题在于它非常高级,这意味着您无法访问低级功能,例如生成线程,然后重新使用它。因此,让我明确说明你能做什么以及你能做什么:
假设您不需要任何互斥锁来防范race conditions,可以选择以下选项:
您将最外层的循环并行化,并且将使用3个线程,这是您将拥有的最和平的解决方案
您将第一个内部循环并行化,然后如果为每个WIDTH元素生成新线程的开销小得多,那么您将只有 需要执行最内循环。
并行化最内层的循环,但这是世界上最糟糕的解决方案,因为你将3 * HEIGHT次重新生成线程。永远不要那样做!
不使用OpenMP,并使用低级别的东西,例如std::thread
,您可以在其中创建自己的线程池,并推送您想要在队列中执行的所有操作。
希望这有助于把事情放在眼里。
答案 2 :(得分:1)
这是另一个选项,它认识到当只有3个循环时,分配最外层循环的迭代可能会导致负载平衡非常差,
i=0
#pragma omp parallel for
for(int j = 0; j < HEIGHT; ++j){
for(int k = 0; k < WIDTH; ++k){
...
}
i=1
#pragma omp parallel for
for(int j = 0; j < HEIGHT; ++j){
for(int k = 0; k < WIDTH; ++k){
...
}
i=2
#pragma omp parallel for
for(int j = 0; j < HEIGHT; ++j){
for(int k = 0; k < WIDTH; ++k){
...
}
警告 - 自己检查一下语法,这只不过是手动循环展开的草图。
尝试将其合并并折叠j
和k
循环。
哦,不要抱怨代码重复,你告诉我们你的性能提升部分得分。