2015-12-16 3 views
4

Я изучаю openmp, используя пример вычисления значения pi через квадратуру. В последовательной, я бегу следующий код C:Оптимизация компилятора OpenMP vs gcc

double serial() { 
    double step; 
    double x,pi,sum = 0.0; 

    step = 1.0/(double) num_steps; 

    for (int i = 0; i < num_steps; i++) { 
     x = (i + 0.5) * step; // forward quadature 
     sum += 4.0/(1.0 + x*x); 
    } 
    pi = step * sum; 

    return pi; 
} 

Я сравнивая это с реализацией OMP, используя параллельно с уменьшением для:

double SPMD_for_reduction() { 
    double step; 
    double pi,sum = 0.0; 

    step = 1.0/(double) num_steps; 

    #pragma omp parallel for reduction (+:sum) 
    for (int i = 0; i < num_steps; i++) { 
     double x = (i + 0.5) * step; 
     sum += 4.0/(1.0 + x*x); 
    } 
    pi = step * sum; 

    return pi; 
} 

Для num_steps = 1000000000 и 6 нитей в случай OMP, компилировать и время:

double start_time = omp_get_wtime(); 
    serial(); 
    double end_time = omp_get_wtime(); 

    start_time = omp_get_wtime(); 
    SPMD_for_reduction(); 
    end_time = omp_get_wtime(); 

не используя куб.см оптимизации компилятора, среды выполнения вокруг 4s (последовательный) и .66s (OMP). С флагом -O3 серийное время выполнения падает до «.000001s», а время выполнения omp в основном не изменяется. Что тут происходит? Используются ли эти векторные инструкции, или это плохой код или метод синхронизации? Если это векторизация, почему функция omp не пользуется?

Может показаться, что используемая мной машина использует современный 6-ядерный процессор Xeon.

Спасибо!

+1

Как насчет просмотра выхода компилятора (код сборки)? – MikeCAT

+9

https://en.wikipedia.org/wiki/Dead_code_elimination – Mysticial

+1

Известно ли значение num_steps во время компиляции? Если это так, вы можете попытаться передать его как параметр времени выполнения через stdin. Посмотрите, если это имеет значение. Если его значение жестко закодировано, возможно, компилятор может заменить цикл for простым выражением, имеющим эквивалентный результат. – RunFun

ответ

2

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

double start_time = omp_get_wtime(); 
serial(); //<-- Computations not used. 
double end_time = omp_get_wtime(); 

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

Вы можете, конечно, написать что-то вроде double serial_pi = serial();, а за пределами измерения времени сделать некоторые фиктивные вещи с переменной serial_pi. Таким образом, компилятор сохранит вызов функции и выполнит оптимизацию, которую вы действительно ищете.

Смежные вопросы