我有一个代码
(Floyd-Warshall algorithm表示NxN
矩阵中的最短路径),有三个 for
-loops,一个在另一个内,并具有相同的周期数。
在上一个 for
中,我通过三元操作= <bool> ? <val1> : <val2>
进行了分配 - 基于比较,如果它是True
。< / p>
我使用OpenMP将第二个 for
与 #pragma omp
parallel for
并行化。
我无法计算代码的并行百分比和序列百分比,以成功应用Amdahl Law来恢复理论加速。
for (k = 0; k < N; k++)
#pragma omp parallel for private(i,j) shared(x) num_threads(4)
for (i = 0; i < N; i++){
for (j = 0; j < N; j++) {
x[i][j] = x[i][j] < (x[i][k] + x[k][j]) ? x[i][j] : (x[i][k] + x[k][j]) ;
}
}
我使用四个核心,所以我希望理论上的加速比为4。
X[i][j]
是矩阵,其中每个元素都充当连接节点i
和j
的边的权重;如果他们没有连接,那就是宏INF
(无限)。
答案 0 :(得分:0)
<强> TL; DR:强>
很高兴大学在Amdahl's Law实例中花费更多时间来展示营销女孩和男孩如何轻易地创造出对多核和多核玩具的错误期望。
那就是说,让我们定义测试用例:
Amdahl's Law声明任何流程整体&#34;改进&#34;的最终限制,因为第[6]节包含要评估的[IUT],而整体&#34;改进&#34;永远不会比~ 1 / ( ( 1 - IUT ) + ( IUT / N ) )
好。
有些读者可以测试并记录实验( 1 - IUT )
部分的时间。
[IUT]
的效果?首先,让我们关注原始发布的代码中发生的事情,在纯SEQ
(串行)代码执行流程中:
即使没有基于OpenMP的尝试将任务分配到更大的资源基础上,初始代码片段已经有了一些提升性能的空间:
for ( k = 0; k < N; k++ )
for ( i = 0; i < N; i++ ){
for ( j = 0; j < N; j++ ){
x[i][j] = x[i][j] > ( x[i][k] + x[k][j] ) // .TEST <bool>
? ( x[i][k] + x[k][j] ) // .ASSIGN <val1>
: x[i][j]; // .ASSIGN <val2>
}
}
如果这是纯粹SEQ
独奏或尝试利用#pragma omp
,则会在原始问题in both cases the Amdahl's Law will show ZERO or even "negative" improvement.
因为代码被指示运行&#34;机械地&#34;重复所有资源,完全相同,完全相同的任务范围,完全4次,肩并肩,每一个除了其他,所以4倍的资源没有带来任何预期的积极影响,因为他们有他们一起花了相同的时间共同完成任务的所有部分4次,每次在其他部分上独立完成。潜力&#34;帮助&#34; (如果不是更糟,由于某些情况,在整个任务运行期间观察到资源争用时)。
所以,让我们使用OpenMP优势来分割任务,并让每个资源处理算法范围的适当部分(感谢Floyd-Warshall算法,因为这个在这个方向上是非常宽容的并允许这样,因为它的处理方案,即使允许负权重,也是非干预的,所以不需要传播敌对障碍,同步,临界区来传播线程中的任何东西)
#include "omp.h" // .MUST SET a gcc directive // "-fopenmp"
// --------------------------------------------------------[1] ref. above
void main(){
int i, j, k;
const int N = 100;
int x[100][100];
// --------------------------------------------------------[2] ref. above
// --------------------------------------------------------[3] ref. above
// --------------------------------------------------------[4] ref. above
for ( k = 0; k < N; k++ )
{
// --------------------------------------------------------[5] ref. above
//------------------------------------------------------[6]----- OMP
// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// PARALLEL is not precise, "just"-CONCURRENT is EXACT IN THE SECTION LEVEL BELOW
#pragma omp parallel for private(i,j) shared(x) num_threads(4)
for ( i = 0; i < N; i++ ){ // .MUST incl.actual k-th ROW, in case NEG weights are permitted
int nTHREADs = omp_get_num_threads(); // .GET "total" number of spawned threads
int tID = omp_get_thread_num(); // .GET "own" tID# {0,1,..omp_get_num_threads()-1} .AVOID dumb repeating the same .JOB by all spawned threads
for ( j = tID; j < N; j += nTHREADs ){ // .FOR WITH tID#-offset start + strided .INC STEP // .MUST incl.actual k-th COL, in case NEG weights are permitted
// - - - - - - - - - - - - - - - - - - - - - - - -
// SINCE HERE: // .JOB WAS SPLIT 2 tID#-ed, NON-OVERLAPPING tasks
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // .N.B: dumb "just"-CONCURRENT processing is O.K. here
// ................................................ // 1-thread .INC STEP +1 a sure ZERO Amdahl-Law effect ( will bear an adverse penalty from use-less omp_get_*() calls )
// °.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°.°. // 2-threads .INC STEP +2 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 2 ) ) if enough free CPU-resources
// '-.'-.'-.'-.'-.'-.'-.'-.'-.'-.'-.'-.'-.'-.'-.'-. // 3-threads .INC STEP +3 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 3 ) ) if enough free CPU-resources
// ^'-.^'-.^'-.^'-.^'-.^'-.^'-.^'-.^'-.^'-.^'-.^'-. // 4-threads .INC STEP +4 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 4 ) ) if enough free CPU-resources
// o1234567o1234567o1234567o1234567o1234567o1234567 // 8-threads .INC STEP +8 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 8 ) ) if enough free CPU-resources
// o123456789ABCDEFo123456789ABCDEFo123456789ABCDEF // 16-threads .INC STEP +16 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 16 ) ) if enough free CPU-resources
// o123456789ABCDEFGHIJKLMNOPQRSTUVo123456789ABCDEF // 32-threads .INC STEP +32 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 32 ) ) if enough free CPU-resources
// o123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl // 64-threads .INC STEP +64 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 64 ) ) if enough free CPU-resources
// o123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl // 128-threads .INC STEP +128 may have Amdahl-Law effect ~ 1 / ( ( 1 - OMP ) + ( OMP / 128 ) ) if enough free CPU-resources
int aPair = x[i][k] + x[k][j]; // .MUST .CALC ADD( x_ik, x_kj ) to TEST // .MAY smart re-use in case .GT. and ASSIGN will have to take a due place
if ( x[i][j] > aPair ) x[i][j] = aPair; // .IFF .UPD // .AVOID dumb re-ASSIGN(s) of self.value(s) to self
// - - - - - - - - - - - - - - - - - - - - - - - -
}
}
// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}// --------------------------------------------------------------- OMP
return;
}
通过一些有趣的实验,提出的方法为进一步探索开辟了一些潜力:
答案 1 :(得分:-1)
两个内部循环和最内层循环的主体在每个核心上串行执行。那是因为您标记了外部循环并行执行。
可是:
最内层循环中的主体对所有核心使用相同的矩阵,并且还修改矩阵。因此,矩阵的变化必须支持所有其他核心。这可能会导致以下问题:
您应该检查是否可以以不交叉部分矩阵的方式更改算法。如果核心处理单独的不相交数据,您将获得最佳加速。
由于几乎没有这么做,你应该明确地描述它的代码和变体。