我使用的是Why is writing to memory much slower than reading it?中的“读取”基准,我只添加了两行:
#pragma omp parallel for
for(unsigned dummy = 0; dummy < 1; ++dummy)
它们应该没有效果,因为OpenMP should only parallelize the outer loop,但是代码现在始终以两倍的速度运行。
更新:这些行甚至不是必需的。只需添加
omp_get_num_threads();
在同一位置的(隐式声明)具有相同的效果。
完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
unsigned long do_xor(const unsigned long* p, unsigned long n)
{
unsigned long i, x = 0;
for(i = 0; i < n; ++i)
x ^= p[i];
return x;
}
int main()
{
unsigned long n, r, i;
unsigned long *p;
clock_t c0, c1;
double elapsed;
n = 1000 * 1000 * 1000; /* GB */
r = 100; /* repeat */
p = calloc(n/sizeof(unsigned long), sizeof(unsigned long));
c0 = clock();
#pragma omp parallel for
for(unsigned dummy = 0; dummy < 1; ++dummy)
for(i = 0; i < r; ++i) {
p[0] = do_xor(p, n / sizeof(unsigned long)); /* "use" the result */
printf("%4ld/%4ld\r", i, r);
fflush(stdout);
}
c1 = clock();
elapsed = (c1 - c0) / (double)CLOCKS_PER_SEC;
printf("Bandwidth = %6.3f GB/s (Giga = 10^9)\n", (double)n * r / elapsed / 1e9);
free(p);
}
使用
编译并执行gcc -O3 -Wall -fopenmp single_iteration.c && time taskset -c 0 ./a.out
time
报告的挂墙时间是3.4s和7.5s。
GCC 7.3.0(Ubuntu)
答案 0 :(得分:1)
性能差异的原因实际上不是代码上的任何差异,而是内存的映射方式。在快速情况下,您从零页读取数据,即所有虚拟地址都映射到单个物理页-因此无需从内存中读取任何内容。在慢速情况下,它不会归零。有关详细信息,请参见this answer from a slightly different context。
另一方面,它不是由调用omp_get_num_threads
或编译指示ittelf引起的,而仅仅是链接到OpenMP运行时库。您可以使用-Wl,--no-as-needed -fopenmp
进行确认。如果您仅指定-fopenmp
但根本不使用它,则链接器将忽略它。
不幸的是,现在我仍然缺少最后一个难题:为什么链接到OpenMP会改变calloc
关于零页的行为。