Почему OpenMP работает медленно в этом случае? - PullRequest
4 голосов
/ 22 марта 2011

Я пытаюсь понять, почему OpenMP работает так, как в следующем примере.

#include <omp.h>
#include <iostream>
#include <vector>
#include <stdlib.h>

void AddVectors (std::vector< double >& v1,
                 std::vector< double >& v2) {

    size_t i;

#pragma omp parallel for private(i)
    for (i = 0; i < v1.size(); i++) v1[i] += v2[i];

}


int main (int argc, char** argv) {

    size_t N1 = atoi(argv[1]);

    std::vector< double > v1(N1,1);
    std::vector< double > v2(N1,2);

    for (size_t i = 0; i < N1; i++) AddVectors(v1,v2);

    return 0;

}

Сначала я скомпилировал приведенный выше код без включения OpenMP (опуская -fopenmp в флагах компиляции). Время выполнения для N1 = 10000 составляло 0,1 с. Включение OpenMP заставляет время выполнения превышать 1 минута . Я остановил это прежде, чем это было сделано (устал ждать ...).

Я компилирую код как показано ниже:

g ++ -std = c ++ 0x -O3 -funroll-loop -march = core2 -fomit-frame-pointer -Wall -fno-строгий псевдоним -o main.o -c main.cpp

g ++ main.o -o main

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

Кто-нибудь знает, что происходит не так? Спасибо!

Ответы [ 3 ]

2 голосов
/ 30 марта 2013

Я попробовал тот же пример на Visual Studio 2008. Я сделал две модификации в вашем примере кода, и он работает примерно в 3 раза быстрее с OpenMP, чем без OpenMP.

Не имея возможности подтвердить его наGCC, проблема может заключаться в том, что в главном цикле вызывается функция AddVectors, и каждый раз, когда она выполняет операцию «fork», это займет некоторое измеримое время.Поэтому, если у вас N1 = 10000, он должен порождать 10000 «разветвленных» операций.

Я прикрепил ваш собственный фрагмент кода, модифицированный только для работы в Visual Studio, и в конце добавил оператор печатичтобы компилятор не удалял весь код.

#include <omp.h>
#include <iostream>
#include <vector>
#include <stdlib.h>

void AddVectors (std::vector< double >& v1,
                 std::vector< double >& v2) {

    #pragma omp parallel for
    for (int i = 0; i < static_cast<int>(v1.size()); i++) v1[i] += v2[i];

}


int main (int argc, char** argv) {

    size_t N1 = atoi(argv[1]);

    std::vector< double > v1(N1,1);
    std::vector< double > v2(N1,2);

    for (size_t i = 0; i < N1; i++) AddVectors(v1,v2);


    printf("%g\n",v1[0]);
    return 0;

}
1 голос
/ 02 апреля 2013

Проблема с типом массива , который вы используете.

Вектор - это контейнер. Это структура, которая хранит несколько данных, таких как размер, начало, конец и т. Д .; и имеет несколько встроенных функций, где operator [] является одним из них, используемых для доступа к данным. В результате строки кэша, которые имеют тенденцию загружаться, скажем, для индекса "i" вектора V , загружают элемент V [i] и некоторую информацию, которая не используется в код.

Напротив, если вы используете классические массивы (динамические / статические), оператор [] приводит к загрузке только элементов данных. В результате строка кэша (обычно длиной 64 байта) будет загружать 8 элементов этого двойного массива (размер double = 8 байтов).

См. Различие между _mm_malloc и malloc для улучшения выравнивания данных.

@ Мистер Фуз Я не уверен в этом. Давайте сравним результаты производительности для обоих случаев:

4 потока на процессоре i7

Array Time Taken: 0.122007 | Повторите: 4 | MFlops: 327,85

векторное время съемки: 0.101006 | Повторите: 2 | MFlops: 188,669

Я заставляю время выполнения быть более 0,1 сек, поэтому код повторяется. Основной цикл:

const int N = 10000000;
timing(&wcs);
for(; runtime < 0.1; repeat*=2)
{
    for(int r = 0; r < repeat; r++)
    {
        #pragma omp parallel for
        for(int i = 0; i < N; i++)
        {
            A[i] += B[i];
        }
        if(A[0]==0) dummy(A[0]);
    }
    timing(&wce);
    runtime = wce-wcs;
}

MFLops: ((N * повтор) / время выполнения) / 1000000

1 голос
/ 31 марта 2011

Может быть, g ++ оптимизировал целые вызовы AddVectors?Попробуйте вернуть последний элемент v1 и сохранить его в переменной volatile.

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