Метод прямоугольника не параллелится

258
11 мая 2019, 22:10

Здравствуйте пишу простой алгоритм численного метода (прямоугольника). Распараллелил эту функцию с помощью OpenMP. Но время выполнения параллельного алгоритма больше, чем выполнение с одним поток. В чем ошибка? Использую пк с 12 ядрами процессора,999999999 итераций.

const unsigned long numSteps=999999999;                     /* default # of rectangles */
const double PI25DT = 3.141592653589793238462643;
double function(double x) //Подынтегральная функция
{
  return 4.0/(1.+ x*x); //Например, sin(x)
}
double CalcIntegralWithParallel(int countThread) {
   double x, pi = 0;
   double sum=0.0;
   double step = 1./static_cast<double>(numSteps);
 #pragma omp parallel for num_threads(countThread) reduction(+:sum)
    for (int i=0; i<numSteps; i++)
    {
        x = (i + .5)*step;
        sum = sum + function(x);
    }
    pi = sum*step;
    return pi;
}
double CalcIntegral(double a, double b) {
    double x, pi = 0;
    double sum=0.0;
    double step =1./static_cast<double>(numSteps);
    for (int i=0; i<numSteps; i++)
    {
        x = (i + .5)*step;
        sum = sum + function(x);
    }
    pi = sum*step;
    return pi;
}
int main(int argc, char** argv)
{
    double timeStart ,timeStop;
    double pi; 
    double secs;
    timeStart = omp_get_wtime();
    pi = CalcIntegral(8,0);
    timeStop = omp_get_wtime();
    std::cout << "The value of integral is " << pi << " Error is " << fabs(pi - PI25DT) << std::endl;
    std::cout << "The time to calculate integral was " ;
    secs=  timeStop - timeStart;
    std::cout << secs << " seconds\n" << std::endl;
    timeStart = omp_get_wtime();
    pi = CalcIntegralWithParallel(4);
    timeStop = omp_get_wtime();
    std::cout << "The value of PI is OPEN MP 4 " << pi << " Error is " << fabs(pi - PI25DT) << std::endl;
    std::cout << "The time to calculate PI was " ;
    secs=  timeStop - timeStart;
    std::cout << secs << " seconds\n" << std::endl;
    timeStart = omp_get_wtime();
    pi = CalcIntegralWithParallel(8);
    timeStop = omp_get_wtime();
    std::cout << "The value of PI is OPEN MP 8 " << pi << " Error is " << fabs(pi - PI25DT) << std::endl;
    std::cout << "The time to calculate PI was " ;
     secs=  timeStop - timeStart;
    std::cout << secs << " seconds\n" << std::endl;
    timeStart = omp_get_wtime();
    pi = CalcIntegralWithParallel(12);
    timeStop = omp_get_wtime();
    std::cout << "The value of PI is OPEN MP 12 " << pi << " Error is " << fabs(pi - PI25DT) << std::endl;
    std::cout << "The time to calculate PI was " ;
     secs=  timeStop - timeStart;
    std::cout << secs << " seconds\n" << std::endl;
    return 0;
}

Ниже результат выполнения программы:

The value of integral is 3.14159 Error is 7.54952e-15 The time to calculate integral was 11.9711 seconds

The value of PI is OPEN MP 4 3.14162 Error is 2.64888e-05 The time to calculate PI was 20.342 seconds

The value of PI is OPEN MP 8 3.14159 Error is 3.7927e-07 The time to calculate PI was 21.1447 seconds

The value of PI is OPEN MP 12 3.14162 Error is 3.16601e-05 The time to calculate PI was 21.4869 seconds

Answer 1

В общем, как я и говорил, все дело в роли для x. Если программу оставить как есть, то тогда при оптимизации gcc все делает правильно сам, а без оптимизации для x отводится роль общей переменной для потоков (shared - я проверил, установив эту роль для x). Из-за этого получается неверный результат (очень низкая точность) и коллизии при попытке нескольких потоков одновременно записать в эту x. Лечится принудительным указанием, что x должна быть приватной для каждого потока (лучше через firstprivate, чтобы она унаследовала и начальное значение, но это уже не так важно в данной задаче).

Такая прагма решает проблему при неоптимизированной сборке g++ omp.cpp -o o -fopenmp:

 #pragma omp parallel for num_threads(countThread) reduction(+:sum) firstprivate(x)

У меня на i5 Haswell (4 ядра) получились следующие результаты:

  • The value of integral is 3.14159 Error is 2.05835e-012 The time to calculate integral was 16.973 seconds

  • The value of PI is OPEN MP 4 3.14159 Error is 3.55715e-013 The time to calculate PI was 4.556 seconds

  • The value of PI is OPEN MP 8 3.14159 Error is 1.24345e-013 The time to calculate PI was 4.321 seconds

  • The value of PI is OPEN MP 12 3.14159 Error is 1.22125e-013 The time to calculate PI was 4.415 seconds

что является вполне нормальным на мой взгляд.

READ ALSO
Почему stoi выдает ошибку invalid_argument?

Почему stoi выдает ошибку invalid_argument?

Вот фрагмент кода одной из функцийПри первом вызове все проходит на ура

162
Бесконечный цикл в clang, в gcc - работает

Бесконечный цикл в clang, в gcc - работает

Решили добавить тесты для компилятора clang помимо gccВ итоге в одной функции получаем бесконечный цикл, и в минимальном примере размер карты...

192
Передать любой тип как аргумент (с указанием типа) в C++

Передать любой тип как аргумент (с указанием типа) в C++

Видел в некоторых исходниках конструкцию типа Function<DWORD>(123)Подскажите пожалуйста:

202