Почему OpenMP ускоряет цикл SINGLE-ITERATION? - PullRequest
0 голосов
/ 11 марта 2019

Я использую тест "read" из Почему запись в память намного медленнее, чем чтение? , и я добавил только две строки:

#pragma omp parallel for
for(unsigned dummy = 0; dummy < 1; ++dummy) 

Они не должны иметь никакого эффекта, потому что OpenMP должен только распараллеливать внешний цикл , но код теперь последовательно выполняется в два раза быстрее.

Обновление: Эти строки даже не нужны. Просто добавив

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,4 с против 7,5 с.

GCC 7.3.0 (Ubuntu)

1 Ответ

1 голос
/ 11 марта 2019

Причиной разницы в производительности является не какая-либо разница в коде, а в том, как отображается память. В быстром случае вы читаете с нулевых страниц, то есть все виртуальные адреса отображаются на одной физической странице, поэтому ничего не нужно читать из памяти. В медленном случае он не обнуляется. Подробнее см. этот ответ в несколько ином контексте .

С другой стороны, это вызвано не вызовом omp_get_num_threads или прагмой itstelf, а простой ссылкой на библиотеку времени выполнения OpenMP. Вы можете подтвердить это, используя -Wl,--no-as-needed -fopenmp. Если вы просто укажете -fopenmp, но не используете его вообще, компоновщик его пропустит.

Теперь, к сожалению, я до сих пор скучаю по последней части головоломки: почему ссылки на OpenMP изменяют поведение calloc относительно нулевых страниц.

...