C++ 使用C+中的OpenMP,矩阵乘法的性能保持不变+; auto t1=chrono::staid_clock::now(); #pragma-omp并行 { 对于(int i=0;i
而言,C++ 使用C+中的OpenMP,矩阵乘法的性能保持不变+; auto t1=chrono::staid_clock::now(); #pragma-omp并行 { 对于(int i=0;i,c++,openmp,codeblocks,C++,Openmp,Codeblocks,而言,collapse指令实际上可能对此负责,因为索引j是使用重新创建的 您是否尝试过不使用collapse?collapse指令实际上可能对此负责,因为索引j是使用重新创建的 您是否尝试过不使用collapse?建议的OpenMP并行化是不正确的,可能会导致错误的结果。当指定collapse(2)时,线程“同时”执行(j,k)迭代。如果两个(或更多)线程在相同的j上工作,但不同的k,它们会累积A[i][k]*B[k][j]的结果到相同的数组位置C[i][j]。这是一种所谓的争用条件,即“两个或
collapse
指令实际上可能对此负责,因为索引j
是使用重新创建的
您是否尝试过不使用
collapse
?collapse
指令实际上可能对此负责,因为索引j
是使用重新创建的
您是否尝试过不使用
collapse
?建议的OpenMP并行化是不正确的,可能会导致错误的结果。当指定collapse(2)
时,线程“同时”执行(j,k)迭代。如果两个(或更多)线程在相同的j上工作,但不同的k,它们会累积A[i][k]*B[k][j]的结果
到相同的数组位置C[i][j]
。这是一种所谓的争用条件,即“两个或多个线程可以访问共享数据,并试图同时更改它”()。数据争用不一定会导致错误的结果,尽管代码不是OpenMP有效的,并且可能会根据几个因素产生错误的结果(调度、编译器实现、线程数等)。为了解决上述代码中的问题,OpenMP提供了reduce
子句:
auto t1 = chrono::steady_clock::now();
#pragma omp parallel
{
for(int i=0;i<n;i++)
{
#pragma omp for collapse(2)
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
C[i][j]+=A[i][k]*B[k][j];
}
}
}
}
auto t2 = chrono::steady_clock::now();
auto t = std::chrono::duration_cast<chrono::microseconds>( t2 - t1 ).count();
使用reduction时,性能损失是巨大的(反向加速)。外部并行化(w或w/o崩溃)是最好的选择
关于大型矩阵的失败,一个可能的原因与可用堆栈的大小有关。请尝试扩大系统和OpenMP堆栈的大小,即
Serial 418020
----------- WRONG ORIG -- +REDUCTION -- OUTER.COLLAPSE -- OUTER.NOCOLLAPSE -
OpenMP-1 1924950 2841993 1450686 1455989
OpenMP-2 988743 2446098 747333 745830
OpenMP-4 515266 3182262 396524 387671
OpenMP-8 280285 5510023 219506 211913
OpenMP-16 2227567 10807828 150277 123368
建议的OpenMP并行化不正确,可能会导致错误的结果。当指定
collapse(2)
时,线程“同时”执行(j,k)迭代。如果两个(或更多)线程在相同的j上工作,但k不同,则它们将A[i][k]*B[k][j]的结果累积到相同的数组位置C[i][j]
。这是一种所谓的争用条件,即“两个或多个线程可以访问共享数据,并试图同时更改它”()。数据争用不一定会导致错误的结果,尽管代码不是OpenMP有效的,并且会根据多个因素产生错误的结果(调度、编译器实现、线程数等)。为了解决上述代码中的问题,OpenMP提供了reduce
子句:
auto t1 = chrono::steady_clock::now();
#pragma omp parallel
{
for(int i=0;i<n;i++)
{
#pragma omp for collapse(2)
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
C[i][j]+=A[i][k]*B[k][j];
}
}
}
}
auto t2 = chrono::steady_clock::now();
auto t = std::chrono::duration_cast<chrono::microseconds>( t2 - t1 ).count();
使用reduction时,性能损失是巨大的(反向加速)。外部并行化(w或w/o崩溃)是最好的选择
关于大型矩阵的失败,一个可能的原因与可用堆栈的大小有关。请尝试扩大系统和OpenMP堆栈的大小,即
Serial 418020
----------- WRONG ORIG -- +REDUCTION -- OUTER.COLLAPSE -- OUTER.NOCOLLAPSE -
OpenMP-1 1924950 2841993 1450686 1455989
OpenMP-2 988743 2446098 747333 745830
OpenMP-4 515266 3182262 396524 387671
OpenMP-8 280285 5510023 219506 211913
OpenMP-16 2227567 10807828 150277 123368
这看起来更有利于外循环上的并行性。正如其他人所暗示的,包括崩溃中的内循环可能会排除线程内的重要优化。在不首先优化单个线程的情况下抛出并行性无论如何都有局限性。这看起来更有利于外循环上的并行性。正如其他人所暗示的,包括内循环折叠中的op可能会排除线程中的重要优化。在没有对单个线程进行优化的情况下抛出并行性无论如何都有局限性。你的建议奏效了,但我仍然不明白在这里使用折叠有什么问题。另外,如果我将其设置为n=500,为什么我的程序会崩溃?你的建议奏效了,但我不明白仍然不明白在这里使用collapse有什么错。另外,如果我把它设为n=500,为什么我的程序会崩溃?谢谢你给出了详细的答案,但问题是我得到了正确的答案,尽管我在使用collapse时没有使用reduce。另外,当n远大于处理器collapse的数量时,我得到了正确的答案但是,如果我把n变成500,我的程序崩溃了,原因是什么?我如何改变C++中的大小?我找不到改变OMP栈大小的方法,并且我得到一个错误:LIGBGOMP:线程创建失败:RESURce暂时不可用。请尝试较小的OMP_STACKSIZE值。在我的计算机上,上面的数字有效,但取决于计算机。我的计算机是windows计算机…它无法识别OMP_STACKSIZE内容请尝试编译设置适当的STACKSIZE(足够大以承载静态内存,但在使用多个线程运行时不会太大以拥有足够的资源)使用命令提示符。对于n=1000,我建议:g++-std=c++11-Wl,--stack,13000000-fopenmp so.cpp
。然后尝试使用set-OMP_NUM_threads=1
设置线程数,然后增加线程数。感谢您提供的详细答案,但问题是,尽管我没有使用不要在崩溃时使用缩减。此外,我发现当n远大于处理器数量时,可能不需要崩溃。不过,根据我的说法,它应该比串行程序有一定的性能提升。此外,如果我将n设为500左右,我的程序会崩溃。原因可能是什么?如何更改C中的大小++?我找不到更改omp堆栈大小的方法,出现错误“libgomp:线程创建失败:资源暂时不可用”。请尝试较小的omp_STACKSIZE值。在我的计算机上,上面的数字起作用,但取决于计算机。我的计算机是windows计算机…它无法识别omp_STACKSIZE内容尝试编译设置adequate stacksize(足够大以承载静态内存,但在使用多个线程运行时不会太大以拥有足够的资源)使用命令提示符。对于n=1000,我建议:g++-std=c++11-Wl,--stack,13000000-fopenmp so.cpp
。然后尝试使用set OMP_NUM_threads=1
运行设置线程数,然后增加线程数。
ulimit -s unlimited
export OMP_STACKSIZE=10000000