C ++ OpenMP работает очень медленно на матрично-векторном продукте - PullRequest
0 голосов
/ 02 марта 2019

Итак, я делаю матрично-векторный продукт с использованием openMP, но я заметил, что он работает очень медленно.После нескольких попыток выяснить, в чем дело, я просто удалил весь код в параллельном разделе, и он все еще МЕДЛЕН.В чем тут может быть проблема?(n = 1000)

Вот результаты времени для 1, 2 и 4 ядер.

seq_method time = 0,001047194215062

parrallel_method (1) time = 0,001050273191140 seq - par = -0,000003078976079 seq / par = 0,997068404578433

2 241 0262 026 026 0260000 = 2 026 026 026 026 026 026 026 026 026 026 026 600seq - par = -0.000914798210943 seq / par = 0.533740192460558

parrallel_method (4) time = 0.004448095121916 seq - par = -0.003400900906854 seq / par = 0.235425319459132

когда код из 1014 * *1013* *параллельная секция - она ​​не сильно меняется.

void parallel_method(float A[n][n], float B[n], float C[n], int thr_num)
{
    double t1, t2;
    float tmp = 0;
    int i, j;
    t1 = omp_get_wtime();


    omp_set_dynamic(0);
    omp_set_num_threads(thr_num);
#pragma omp parallel for private(tmp, j, i)
    for (i = 0; i < n; i++) {
        tmp = 0;
        for (j = 0; j < n; j++) {
            tmp += A[i][j] * B[j];
        }
#pragma omp atomic
        C[i] += tmp;
    }

    //////
    t2 = omp_get_wtime();
    if (show_c) print_vector(C);
    par = t2 - t1;
    printf("\nparrallel_method (%d) time = %.15f", thr_num, par);
    printf("\nseq - par = %.15f", seq - par);
    printf("\nseq/par = %.15f\n", seq / par);
}

Код: https://pastebin.com/Q20t5DLk

1 Ответ

0 голосов
/ 02 марта 2019

Я пытался воспроизвести вашу проблему и не смог этого сделать.У меня совершенно связное поведение.

n=100
sequential_method (0) time = 0.000023339001928
parallel_method (1) time = 0.000023508997401
parallel_method (2) time = 0.000013864002540
parallel_method (4) time = 0.000008979986887

n=1000
sequential_method (0) time = 0.001439775005565
parallel_method (1) time = 0.001437967992388
parallel_method (2) time = 0.000701391996699
parallel_method (4) time = 0.000372130998080

n=10000
sequential_method (0) time = 0.140988592000213
parallel_method (1) time = 0.133375317003811
parallel_method (2) time = 0.077803490007180
parallel_method (4) time = 0.044142695999355

За исключением небольшого размера, где накладные расходы на поток значительны, результаты более или менее ожидаемые.

Что я сделал:

  • все измерения выполняются в одном и том же цикле

  • Я запускаю все функции один раз без времени для прогрева кешей

В реальном кодеоценки, я бы также

  • время несколько последовательных выполнений одной и той же функции, особенно если времени мало, чтобы уменьшить небольшие вариации

  • Проведите несколько экспериментов и оставьте самый маленький, чтобы подавить выбросы.(Я предпочитаю минимум, но вы также можете рассчитать среднее).

Вы должны были опубликовать весь свой код, и я не знаю, какова ваша методология.Но я думаю, что ваши оценки были сделаны разными прогонами и без прогрева кешей.Для этого кода влияние кэша очень важно, и ядра должны хранить одну и ту же информацию (B).И проблема недостаточно велика, чтобы извлечь выгоду из больших кешей L1 / L2.Эти кратные загрузки могут объяснить худшие характеристики параллельного кода.

Последнее замечание в вашем коде.У каждого потока будут свои значения i.Следовательно, C [i] может быть доступен только одному потоку, и атомарная прагма бесполезна.

...