[英]Why is parallel execution slower than sequential for this code?
#pragma omp parallel
{
for (i=1; i<1024; i++)
#pragma omp for
for (j=1; j<1024; j++)
A[i][j] = 2*A[i-1][j];
}
我正在使用12个线程来执行此代码。 有什么建议我必须加快速度吗?
假设A的类型小于64Byte,尝试以这种方式并行化内部循环很可能会导致您在缓存行中共享错误。
假设A是4字节整数的对齐数组,则在同一缓存行中将具有A [i] [0]至A [i] [15]。 这意味着所有12个线程都将尝试同时读取该行,每个线程都需要读取该行,如果您将其留在那,则可能导致该行在多个内核之间共享,但是您还尝试写回去,导致每个核心尝试拥有所有权以进行修改。
CPU缓存通常基于基于MESI的协议,使存储尝试发出所有权的读取,这将使除请求者之外的每个其他内核中的行无效。 发出12个并行信号(如果您有6个核心* 2个线程,则发出6个并行信号)将导致比赛,其中第一个赢得该线路的人很可能在没有机会对其进行修改之前就抢先一步抢走了他(虽然不太可能)。 结果是非常混乱的,并且可能需要一段时间才能将生产线依次转到每个核心,然后进行修改,然后被另一个核心侦听。 下一个连续的16个元素组中的每个重复出现一次(同样,假定为int)。
您可能会做的是:
但是,这将使您无法充分利用CPU的潜力,因为您会丢失代码的空间局部性和流属性。 相反,您可以:
这里仍然有一个缺点,因为如果线程遇到太多的流,可能会失去对它们的跟踪。 因此,第三种方法是-
1)您拥有几个核心? 您无法获得比这更多的并行化速度,而且正如其他人所说的那样,可能要少得多。
2)看起来内部索引j
应该从0开始,而不是1。
3)内循环正在为指针和展开呐喊,就像
double* pa = &A[i][0];
double* pa1 = &A[i-1][0];
for (j = 0; j < 1024; j += 8){
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
*pa++ = 2 * *pa1++;
}
要么...
double* pa = &A[i][0];
double* paEnd = &A[i][1024];
double* pa1 = &A[i-1][0];
for (; pa < paEnd; pa += 8, pa1 += 8){
pa[0] = 2 * pa1[0];
pa[1] = 2 * pa1[1];
pa[2] = 2 * pa1[2];
pa[3] = 2 * pa1[3];
pa[4] = 2 * pa1[4];
pa[5] = 2 * pa1[5];
pa[6] = 2 * pa1[6];
pa[7] = 2 * pa1[7];
}
以较快者为准。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.