Open MP плохая / запутанная производительность - PullRequest
0 голосов
/ 19 февраля 2019

Ниже приведен код Тима Мэттсона из его серии видео на Open MP.Единственным изменением, которое я сделал, было увеличение количества потоков до 24, поскольку у меня 24-ядерный компьютер.Он работает не так хорошо, как следовало бы, и я озадачен, почему (см. Результаты ниже).Я что-то здесь упускаю?Я должен упомянуть, что я теоретик-компьютерщик с опытом работы с алгоритмами, но я немного заржавел, когда дело доходит до аппаратного обеспечения.

#include <stdio.h>
#include <omp.h>
static long num_steps = 100000000;
double step;
int main ()
{
  int i;
  double x, pi, sum = 0.0;
  double start_time, run_time;

  step = 1.0/(double) num_steps;
  for (i=1;i<=24;i++){
    sum = 0.0;
    omp_set_num_threads(i);
    start_time = omp_get_wtime();
#pragma omp parallel  
    {
#pragma omp single
      printf(" num_threads = %d",omp_get_num_threads());

#pragma omp for reduction(+:sum)
      for (i=1;i<= num_steps; i++){
          x = (i-0.5)*step;
          sum = sum + 4.0/(1.0+x*x);
      }
    }

    pi = step * sum;
    run_time = omp_get_wtime() - start_time;
    printf("\n pi is %f in %f seconds and %d threads\n",pi,run_time,i);
  }
}

Я ожидаю, что с 24 ядрами это будет в 20-24 раза быстрее, но это едва ли в два раза быстрее.Зачем?!Вот вывод:

 num_threads = 1
 pi is 3.141593 in 1.531695 seconds and 1 threads
 num_threads = 2
 pi is 3.141594 in 1.405237 seconds and 2 threads
 num_threads = 3
 pi is 3.141593 in 1.313049 seconds and 3 threads
 num_threads = 4
 pi is 3.141592 in 1.069563 seconds and 4 threads
 num_threads = 5
 pi is 3.141587 in 1.058272 seconds and 5 threads
 num_threads = 6
 pi is 3.141590 in 1.016013 seconds and 6 threads
 num_threads = 7
 pi is 3.141579 in 1.023723 seconds and 7 threads
 num_threads = 8
 pi is 3.141582 in 0.760994 seconds and 8 threads
 num_threads = 9
 pi is 3.141585 in 0.791577 seconds and 9 threads
 num_threads = 10
 pi is 3.141593 in 0.868043 seconds and 10 threads
 num_threads = 11
 pi is 3.141592 in 0.797610 seconds and 11 threads
 num_threads = 12
 pi is 3.141592 in 0.802422 seconds and 12 threads
 num_threads = 13
 pi is 3.141590 in 0.941856 seconds and 13 threads
 num_threads = 14
 pi is 3.141591 in 0.928252 seconds and 14 threads
 num_threads = 15
 pi is 3.141592 in 0.867834 seconds and 15 threads
 num_threads = 16
 pi is 3.141593 in 0.830614 seconds and 16 threads
 num_threads = 17
 pi is 3.141592 in 0.856769 seconds and 17 threads
 num_threads = 18
 pi is 3.141591 in 0.907325 seconds and 18 threads
 num_threads = 19
 pi is 3.141592 in 0.880962 seconds and 19 threads
 num_threads = 20
 pi is 3.141592 in 0.855475 seconds and 20 threads
 num_threads = 21
 pi is 3.141592 in 0.825202 seconds and 21 threads
 num_threads = 22
 pi is 3.141592 in 0.759689 seconds and 22 threads
 num_threads = 23
 pi is 3.141592 in 0.751121 seconds and 23 threads
 num_threads = 24
 pi is 3.141592 in 0.745476 seconds and 24 threads

Итак, что мне не хватает?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

В общем случае с многопоточностью для ускорения необходимо учитывать две вещи:

  • Размер задачи и ее части достаточно подходят для распараллеливания
  • Затраты самой распараллеливания (например, создание потоков, уничтожение потоков и т. Д.)

Закон Амдала дает нам некоторый контекст в этом.Давайте будем щедрыми и предположим, что часть кода, которая выиграет от этого ускорения (p), равна 0,5, или половине кода.Ваше утверждение, что это сделает код в 24 раза быстрее (что означает s = 24), приводит к:

enter image description here

Так что в теория вы получаете в 1,92 раза лучшую производительность, а это не то улучшение, на которое вы рассчитывали в 24 раза.

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

0 голосов
/ 19 февраля 2019

У вас есть одна переменная x, которая используется всеми потоками.

Хотя компилятор оптимизирует ее использование, так что вы все равно получите правильный результат (сохраняя вычисленное значение для x врегистр), это значение записывается в память каждую итерацию.Это создаст задержки, когда строки кэша сбрасываются и перезагружаются.

Исправление заключается в объявлении x в теле цикла, в котором вы его используете (double x = (i-0.5)*step;), а не в верхней части main.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...