C 为什么OpenMP会加速单次迭代循环?

C 为什么OpenMP会加速单次迭代循环?,c,performance,gcc,memory,openmp,C,Performance,Gcc,Memory,Openmp,我使用的是来自的read基准,我只添加了两行: #pragma omp parallel for for(unsigned dummy = 0; dummy < 1; ++dummy) 在同一位置隐式声明具有相同的效果 完整代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> unsigned long do_xor(const

我使用的是来自的read基准,我只添加了两行:

#pragma omp parallel for
for(unsigned dummy = 0; dummy < 1; ++dummy) 
在同一位置隐式声明具有相同的效果

完整代码:

#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);
}
时间报告的墙时间为3.4s vs 7.5s


GCC 7.3.0 Ubuntu

性能差异的原因实际上不是代码上的差异,而是内存的映射方式。在快速情况下,您从零页读取,即所有虚拟地址都映射到单个物理页,因此无需从内存读取任何内容。在慢速情况下,它不会归零。有关详细信息,请参阅

另一方面,它不是由调用omp_get_num_线程或pragma itstelf引起的,而只是链接到OpenMP运行库。您可以根据需要使用-Wl,-no-fopenmp来确认这一点。如果只指定-fopenmp,但根本不使用它,链接器将忽略它


现在不幸的是,我仍然没有找到最后一个谜题:为什么链接到OpenMP会改变calloc关于零页面的行为。

我可以重现。这不是优化,也不是时钟的问题。尽管如此,我建议您可以通过测量墙时间来改进问题,并添加实际测量结果以及您的CPU和内存规格。-fopenmp可能使用不同的线程安全版本的calloc?
#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