正在测试和计时某些计算(试图找到一个比我的处理器上的所有4个线程并行运行速度快4倍的for循环)当我注意到这个不会以100%cpu使用率运行尽管编译器报告它是并行化的。它只能以25%的CPU使用率运行。我的处理器上的每个核心都应该有自己的arr4副本,这是一个在堆栈上分配的C样式数组,每个核心应该重复修改该堆栈数组的每个值。最后,计时器打印以秒为单位的时间。如果并行化的时间需要40秒,我希望没有并行化的for循环的时间不到4 * 40秒或160秒。优化设置为最大速度,物理内存上的堆栈大小设置为8亿字节(以防止堆栈溢出)。无论如何,这是下面的测试代码......
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
int main (void)
{
clock_t begin, end;
double time_spent;
begin = clock();
{
//int j;
#pragma loop(hint_parallel(4))
#pragma loop(ivdep)
for (int j=0; j < 8; ++j)
{
int * __restrict const arr4 = (int *) _alloca(16000000*sizeof(int));
for (int z = 0; z < 16000000; ++z)
{
arr4[z] = z;
}
#pragma loop(no_vector)
for (int i = 0; i < 16000000; ++i)
{
for (int k = 0; k < 160; ++k)
{
arr4[i] -= (7 - arr4[i] * 6 % (i+77) + 5 * 4 / 3 + 3 % 2 + 1 - (i+7));
arr4[i] += ((77 - 2 - (i+9)/2 + arr4[i]));
arr4[i] *= (8 - 2 + 6 % 3 / 2 + (i+6));
}
}
printf(" %i ", arr4[((j+1)*666)%16]);
}
}
end = clock();
time_spent = (double)(end - begin) / ((double)CLOCKS_PER_SEC);
printf("Test1: time as a floating point type is %f \n", time_spent);
return 0;
}
此修订示例也会产生相同的25%CPU问题。
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
int main (void)
{
clock_t begin, end;
double time_spent;
begin = clock();
int * __restrict const arr4 = (int *) _alloca(16000000*sizeof(int));
#pragma loop(hint_parallel(4))
#pragma loop(ivdep)
for (int j=0; j < 8; ++j)
{
for (int i = 0; i < 16000000; ++i)
{
int v = i; // eliminate initialization pass (z loop)
for (int k = 0; k < 160; ++k)
{
v -= (7 - v * 6 % (i+77) + 5 * 4 / 3 + 3 % 2 + 1 - (i+7));
v += ((77 - 2 - (i+9)/2 + v));
v *= (8 - 2 + 6 % 3 / 2 + (i+6));
}
arr4[i] = v;
}
//printf(" %i ", arr4[((j+1)*666)%16]);
}
end = clock();
//time_spent = (double)(end - begin) / ((double)CLOCKS_PER_SEC);
time_spent = (double)(end - begin);
printf(" %i ", arr4[666]);
printf("Test1: time as a floating point type is %f \n", time_spent);
return 0;
}
答案 0 :(得分:4)
首先,您不应期望在添加处理器时提高线性速度。在理想条件下,将可用内核数量加倍通常只能将执行时间提高约1.8倍。
从人的角度考虑:将10人开发团队加倍到20人会自动让你完成两倍的工作吗?不,因为随着参与者人数的增加,沟通和协调成为一项更大的任务。
其次,你的定时器循环中有很多非计算的东西。你的外部循环中有内存分配和printf,你的内循环中有多个内存读写。特别是,您正在读取内存地址,写入内容,再次读取它等等,这可能会使某些寄存器变量编译器优化无效。
很可能你的cpu花了很多时间等待内存读写完成。
由于您对数组中数据的修改似乎对外部观察者不可见,您应该考虑将arr4 [i]值拉入本地int变量并对该本地int变量执行所有操作,然后写入将local int变量返回到arr4 [i]内存地址。这样可以减少5次读取的内存负载,3次写入1次读取,1次内部循环迭代写入,并消除代价高昂的读写后管道停顿。
由于这些存储器写入发生在k循环内部,因此将初始加载和最终存储移出k循环将减少每次迭代的(5 + 3)* 160 = 1280内存I / O的内存负载i循环每次迭代循环到2个内存I / O.哦,整个初始化循环(z循环)也可以被消除,因为初始值是迭代计数。因此,我们可以将内存I / O减少到每次迭代1次。
这样的事情:
for (int j=0; j < 8; ++j)
{
int * __restrict const arr4 = (int *) _alloca(16000000*sizeof(int));
for (int i = 0; i < 16000000; ++i)
{
int v = i; // eliminate initialization pass (z loop)
for (int k = 0; k < 160; ++k)
{
v -= (7 - v * 6 % (i+77) + 5 * 4 / 3 + 3 % 2 + 1 - (i+7));
v += ((77 - 2 - (i+9)/2 + v));
v *= (8 - 2 + 6 % 3 / 2 + (i+6));
}
arr4[i] = v;
}
printf(" %i ", arr4[((j+1)*666)%16]);
}
编译器无法始终进行此优化,因为内存写入通常被认为是神圣的,因为它们可以被当前上下文之外的未知方观察到。如果您不仅仅了解编译器的情况,那么您可以编写比编译器更好的代码。