我通过98306 2D数组初始化了一个庞大的98306。我创建了一个内核函数,该函数计算低于某个阈值的元素总数。
#pragma omp parallel for reduction(+:num_below_threshold)
for(row)
for(col)
index = get_corresponding_index(row, col);
if (array[index] < threshold)
num_below_threshold++;
出于基准目的,我测量了线程数设置为1时内核执行的执行时间。我注意到内核第一次执行大约需要11秒。下一次对在一个线程上在同一阵列上执行的内核的调用仅花费了大约3秒钟。我认为这可能是与缓存有关的问题,但似乎并不相关。造成这种情况的可能原因是什么?
此数组初始化为:
float *array = malloc(sizeof(float) * 98306 * 98306);
for (int i = 0; i < 98306 * 98306; i++) {
array[i] = rand() % 10;
}
同一内核两次应用于此阵列,第二次执行时间比第一个内核快得多。尽管我在Linux上分配了延迟,但是由于初始化功能,这应该不会成为问题。任何解释都会有所帮助。谢谢!
答案 0 :(得分:4)
由于您没有提供任何Minimal, Complete and Verifiable Example,因此我不得不在这里做出一些疯狂的猜测,但是我非常有信心要解决这个问题。
首先,您必须注意到98,306 x 98,306为9,664,069,636,这远大于一个有符号的32位整数可以存储的最大值(即2,147,483,647)。因此,import autopep8
autopep8.fixcode('your_code')
初始化循环的上限在溢出后可能变为1,074,135,044(就像在我的机器上一样,尽管严格来说,这是未定义的行为,否则可能会发生任何事情),大约比您小9倍。预期的。
因此,现在,在初始化循环之后,操作系统认为实际上只分配了11%的分配内存。但是,您的第一个精简循环在遍历数组的各个元素方面做得很好,由于大约有89%的时间是第一次,因此OS会在那里实际进行内存分配,这需要花费大量时间。时间量。
现在,对于您的第二个缩减循环,所有内存都已正确分配和使用,这使其速度更快。
这就是我所相信的。也就是说,许多其他参数也可以在这里发挥作用,例如: