медленный последовательный «for» с включенным openmp

0

Я пытаюсь использовать openmp и находить странные результаты.

Параллельно "для" быстрее работает с openmp, как и ожидалось. Но серийный "для" работает намного быстрее, когда отключен openmp (без опции /openmp. Vs 2013).

Тестовый код

    const int n = 5000;
    const int m = 2000000;
    vector <double> a(n, 0);

    double start = omp_get_wtime();
    #pragma omp parallel for  shared(a) 
    for (int i = 0; i < n; i++)
    {
        double StartVal = i;

        for (int j = 0; j < m; ++j) 
        {
            a[i] = (StartVal + log(exp(exp((double)i))));
        }
    }

    cout << "omp Time: " << (omp_get_wtime() - start) << endl;

    start = omp_get_wtime();

    for (int i = 0; i < n; i++)
    {
        double StartVal = i;

        for (int j = 0; j < m; ++j)
        {
            a[i] = (StartVal + log(exp(exp((double)i))));
        }
    }

    cout << "serial Time: " << (omp_get_wtime() - start) << endl;

Выход без опции /openmp

0
omp Time: 6.4389
serial Time: 6.37592

Выход с опцией /openmp

0
1
2
3
omp Time: 1.84636
serial Time: 16.353

Правильные ли результаты? Или я делаю что-то неправильно?

  • 2
    Включение OpenMP может препятствовать определенным видам оптимизации компилятора. Вы работаете с Release или с кодом отладки? Внутренний цикл является избыточным и не должен превращать его в двоичный файл в режиме выпуска.
  • 0
    выход для режима выпуска
Теги:
openmp

1 ответ

0
Лучший ответ

Я считаю, что часть ответа скрыта в архитектуре компьютера, на котором вы работаете. Я попробовал запустить тот же код на другой машине (GCC 4.8 на GNU + Linux, четырехъядерный процессор Core2), и во многих прогонах обнаружил немного странную вещь: время для обеих циклов варьировалось, а OpenMP со многими потоками всегда работал быстрее, второй цикл никогда не выполнялся значительно быстрее, чем первый, даже без OpenMP.

Следующим шагом было попытаться устранить зависимость между циклами, выделив второй вектор для второго цикла. Он продолжался не быстрее первого. Поэтому я попытался перевернуть их, запустив цикл OpenMP после последовательного; и в то время как он по-прежнему быстро работал при многопоточности, теперь он видел задержки, когда первый цикл не выполнялся. В настоящее время он больше похож на поведение операционной системы; долгоживущие потоки просто кажутся скорее прерванными. Я предпринял некоторые меры для сокращения прерываний (тонкости -15, определенного набора процессоров), но это не система, предназначенная для бенчмаркинга.

Однако ни один из моих результатов не был таким же экстремальным, как ваш. Мое первое предположение о том, что вызвало вашу большую разницу, заключалось в том, что вы повторно использовали один и тот же массив и сначала запустили параллельный цикл. Это распределит массив на кеши на всех ядрах, что вызовет небольшую дилемму: переносить поток на данные или наоборот; и OpenMP, возможно, выбрал любой дистрибутив, в том числе итерацию i, для потоков i% потоков (как в случае с schedule(static,1)), что, вероятно, повредило бы многопоточную среду выполнения или одну кеглину, каждая из которых могла бы повредить более поздние однопоточные чтения, если она вписывается в per -продавать кеши. Однако все обращения к массиву записываются, поэтому процессору не нужно ждать их в первую очередь.

Таким образом, ваши результаты, безусловно, зависят от платформы и неожиданны. Я бы предложил повторить тест с измененным порядком, две циклы, работающие на разных массивах, и помещенные в разные единицы компиляции, и, конечно, для проверки письменных результатов. Возможно, вы обнаружили недостаток в своем компиляторе.

  • 0
    Я бы подождал, пока ОП не подтвердит, что он компилируется в режиме Release. Мне трудно поверить, что заполнение массива всего 5000 дубликатами log(exp(exp((double)i) должно занять шесть секунд на современных процессорах.
  • 0
    Использование разных векторов для последовательных и параллельных циклов устраняет проблему

Ещё вопросы

Сообщество Overcoder
Наверх
Меню