производительность кода openmp и как сделать его быстрее - PullRequest
1 голос
/ 25 января 2012

Я делаю следующий код, который строит матрицу расстояний между каждой точкой и всеми другими точками, которые у меня есть на карте dat[]. Хотя код работает отлично, производительность кода с точки зрения времени выполнения не улучшается, а это означает, что это займет то же время, если я установлю число потоков = 1 или даже 10 на 8-ядерном компьютере. Поэтому я был бы признателен, если бы кто-нибудь мог помочь мне узнать, что не так в моем коде, и если бы у кого-нибудь было какое-либо предложение помочь сделать код более быстрым, это тоже было бы очень полезно. Ниже приведен код:

map< int,string >::iterator datIt;
map <int, map< int, double> > dist;
int mycont=0;
datIt=dat.begin();
int size=dat.size();
omp_lock_t lock;
omp_init_lock(&lock);
#pragma omp  parallel    //construct the distance matrix
{   
    map< int,string >::iterator datItLocal=datIt;
    int lastIdx = 0;
    #pragma omp for   
    for(int i=0;i<size;i++)
    {
        std::advance(datItLocal, i - lastIdx);
        lastIdx = i;
        map< int,string >::iterator datIt2=datItLocal;
        datIt2++;
        while(datIt2!=dat.end())
        {
            double ecl=0;
            int c=count((*datItLocal).second.begin(),(*datItLocal).second.end(),delm);
            string line1=(*datItLocal).second;
            string line2=(*datIt2).second;
            for (int i=0;i<c;i++)
            {
                double num1=atof(line1.substr(0,line1.find_first_of(delm)).c_str());
                line1=line1.substr(line1.find_first_of(delm)+1).c_str();
                double num2=atof(line2.substr(0,line2.find_first_of(delm)).c_str());
                line2=line2.substr(line2.find_first_of(delm)+1).c_str();
                ecl += (num1-num2)*(num1-num2);
            }
            ecl=sqrt(ecl);
            omp_set_lock(&lock);
            dist[(*datItLocal).first][(*datIt2).first]=ecl;
            dist[(*datIt2).first][(*datItLocal).first]=ecl;
            omp_unset_lock(&lock);
            datIt2++;
        }
    }
}
omp_destroy_lock(&lock);

Ответы [ 2 ]

0 голосов
/ 25 января 2012

Я немного не уверен в том, что именно вы пытаетесь сделать со своими циклами и т. Д., Похоже, он будет делать квадратичный вложенный цикл по карте.Однако, если предположить, что это ожидается, я думаю, что следующая строка будет работать плохо при распараллеливании:

std::advance(datItLocal, i - lastIdx);

Если OpenMP был отключен, это продвигается на один шаг каждый раз, и это нормально.Но с OpenMP будет много потоков, которые будут делать фрагменты этого цикла случайным образом.Таким образом, один из них может начинаться с i = 100000, поэтому он должен пройти 100000 шагов по карте, чтобы начать.Это может случиться довольно часто, если за один раз много потоков получают относительно небольшие фрагменты цикла.Может даже случиться так, что вы в конечном итоге будете ограничены в памяти / кэше, поскольку вам постоянно приходится обходить всю эту предположительно большую карту.Похоже, что это может быть (частью) ваш виновник, так как это может ухудшиться, когда доступно больше потоков.

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

0 голосов
/ 25 января 2012

Я предполагаю, что использование единой блокировки для защиты 'dist' сериализует вашу программу.Вариант 1: рассмотрите возможность использования детальной стратегии блокировки.Как правило, вы получаете выгоду от этого, если dist.size () намного больше, чем количество потоков.

map <int, omp_lock_t  > locks;
...
int key1 = (*datItLocal).first;
int key2 = (*datIt2).first;
omp_set_lock(&(locks[key1]));
omp_set_lock(&(locks[key2]));
dist[(*datItLocal).first][(*datIt2).first]=ecl;
dist[(*datIt2).first][(*datItLocal).first]=ecl;
omp_unset_lock(&(locks[key2]));
omp_unset_lock(&(locks[key1]));

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

   #pragma omp critical
   {
      dist[(*datItLocal).first][(*datIt2).first]=ecl;
      dist[(*datIt2).first][(*datItLocal).first]=ecl;
   }
...