Russian Qt Forum
Ноябрь 23, 2024, 07:18 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Параллельное выполнение цикла расчета  (Прочитано 13260 раз)
Daniel
Гость
« : Ноябрь 22, 2012, 12:38 »

Добрый день. Помогите, кто может Улыбающийся

Происходит огромное количество расчетов вот такого вида:
Код:
for ( int j = 2; j <= MJ - 1; j++)
     for ( k = 2; k <= NK - 1; k++)
          for ( i = 2; i <= *(Radiuses + k) - 1; i++)
          {
                //вычисление нескольких локальных переменных и проверок
                ...
                *(*(*(p1 + i) + j) + k) =  *(*(*(p + i) + j) + k) + /* огромная формула, независящая от p1 */
          }
Хочу сделать, чтобы считало, используя все CPU, т.к. расчеты иногда сутками идут.
Пробую через
Код:
#pragma omp parallel for
, предварительно включив в .pro-файл строку:
Код:
QMAKE_CXXFLAGS += -fopenmp
, а в файл, где происходит расчет, подключил:
Код:
#include <omp.h>

Уже обнаружил такой аспект, что цикл после #pragma omp parallel for не может быть по unsigned int, что исправил объявляя в цикле локальную переменную int j. Также пробовал заменить MJ (который беззнаковый) на int - та же проблема, поэтому вернул его обратно. И как вы уже наверное поняли, помышляю я распараллелить внешний цикл по j.
А проблема такая:
 error: undefined reference to `omp_get_num_threads'
 error: undefined reference to `omp_get_thread_num'
 error: undefined reference to `GOMP_parallel_start'
 error: undefined reference to `GOMP_parallel_end'

ну и как результат:
 error: collect2: ld returned 1 exit status

В гугле не нашел похожих проблем. Скорее всего чего-то где-то я недоподключил. Подскажите, кто может.

Также возможно есть какие более действенные методы для моего случая. Выслушаю советы.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Ноябрь 22, 2012, 12:59 »

Нет самой либы, напр libgomp.a (или др имя на Вашей платформе). Флаг только говорит генерировать код omp
А вообще omp - верный, правильный путь
Записан
Daniel
Гость
« Ответ #2 : Ноябрь 22, 2012, 13:08 »

Нет самой либы, напр libgomp.a (или др имя на Вашей платформе). Флаг только говорит генерировать код omp
А вообще omp - верный, правильный путь
А где ее взять и куда положить?

У меня Win8 Pro x64, использую Qt 4.7.2 for Desktop - MinGW 4.4 (Qt SDK)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 22, 2012, 13:22 »

А где ее взять и куда положить?

У меня Win8 Pro x64, использую Qt 4.7.2 for Desktop - MinGW 4.4 (Qt SDK)
Я использую др IDE поэтому могу только отослать в гуглу  Улыбающийся
Записан
Fat-Zer
Гость
« Ответ #4 : Ноябрь 22, 2012, 14:20 »

А где ее взять и куда положить?

У меня Win8 Pro x64, использую Qt 4.7.2 for Desktop - MinGW 4.4 (Qt SDK)
скорей всего она есть, должна идти в комплекте с gcc. только назавается она libgomp.
не знаю, правда, положили ли её вам в комплект под виндой...
скорей всего она просто не указана для линковки... линкеру соответственно надо просто передать -lgomp. как в qmake это правильно сделать, да ещё и под виндой, я уже и не помню...
« Последнее редактирование: Ноябрь 22, 2012, 14:22 от Fat-Zer » Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #5 : Ноябрь 22, 2012, 15:59 »

как в qmake это правильно сделать, да ещё и под виндой, я уже и не помню...
Если libgomp лежит в стандартной lib папке, то
.pro: -lgomp

Если libgomp лежит не в стандартной lib папке, то
.pro: -L"Путь к папке с библиотекой" -lgomp
Записан
Daniel
Гость
« Ответ #6 : Ноябрь 22, 2012, 16:24 »

Добавил в QtSDK\mingw\lib\
  libgomp.a
а в QtSDK\mingw\bin\
  pthreadGC2.dll

затем в .pro:
  LIBS += -lgomp
  QMAKE_CXXFLAGS += -fopenmp

Теперь компилируется. Но при выполнении #pragma omp parallel for вылетает с ошибкой -1073741819 Грустный


Записан
Daniel
Гость
« Ответ #7 : Ноябрь 22, 2012, 16:37 »

Вроде как проблема в том, что это распараллеливание происходит внутри QThread, но вот решения я так и не нашел Грустный
Записан
ssoft
Гость
« Ответ #8 : Ноябрь 22, 2012, 16:54 »

Небольшой комментарий к коду

Код:
*(*(*(p1 + i) + j) + k) =  *(*(*(p + i) + j) + k)

Вроде как, быстрее быдет работать, к тому же и запись понятнее, если написать (при условии что ***p1 простой тип)

Код:
p1[ i ][ j ][ k ] = p[ i ][ j ][ k ] +
Записан
Daniel
Гость
« Ответ #9 : Ноябрь 22, 2012, 17:10 »

Вроде как, быстрее быдет работать, к тому же и запись понятнее, если написать (при условии что ***p1 простой тип)
Код:
p1[ i ][ j ][ k ] = p[ i ][ j ][ k ] +
Тип простой - float. А почему? Я всегда думал, что при использовании оператора [] происходит проверка на выход за границы массива. А по поводу понятности, то я обычно макросы использую. Но если [] быстрее, то надо будет поправить.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 22, 2012, 17:31 »

Тип простой - float. А почему? Я всегда думал, что при использовании оператора [] происходит проверка на выход за границы массива. А по поводу понятности, то я обычно макросы использую. Но если [] быстрее, то надо будет поправить.
Это не Паскаль, никаких проверок на границы не производится. Скорость выполнения одна и та же, но [] намного легче для восприятия. Использование ** (двух звездочек в объявлении) нежелательно, трех - тем более. 
Записан
Daniel
Гость
« Ответ #11 : Ноябрь 22, 2012, 17:54 »

Это не Паскаль, никаких проверок на границы не производится. Скорость выполнения одна и та же, но [] намного легче для восприятия. Использование ** (двух звездочек в объявлении) нежелательно, трех - тем более. 

Понятно... Значит поправлю как-нибудь, ведь действительно лучше выглядит.

По поводу основной проблемы:
Таки да, это из-за того, что #pragma omp parallel for вызывается из QThread (точнее унаследованного от него класса). Потому что я попробовал в void main() вызвать методы omp - работают.
И как это решить - без понятия, единственное, что нашел, так это обсуждение этой проблемы на каком-то французском форуме (на фр. языке). А решением оказалось вызов где-то метода
Код:
pthread_win32_thread_detach_np (); 
Но я не понял где, да и не работает он у меня (<pthread.h> подключаю).
Может у кого-то какие идеи?
А и еще: то же самое, скомпиленное под линуксом или VS, пашет, в то время как под Mac или на Qt - нет (сам не проверял, но просто с такой проблемой сталкивались люди в темах, что я нагуглил).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Ноябрь 22, 2012, 18:07 »

Используйте omp прямо из главной нитки, ни к чему искать приключений. По умолчанию все ядра будут задействованы. Можно создавать др нитки (через pthread или QThread) но они не будут входить в "бригаду omp". А вот главная нитка входит. Если нужно обновить UI можно напр так

Код
C++ (Qt)
#pragma omp parallel for
for (int i = 0; i < limit; ++i) {
// расчеты
 
#pragma omp master   // код ниже будет выполняться только главной
{
// рисуем в UI
 }
}
 
Записан
Daniel
Гость
« Ответ #13 : Ноябрь 22, 2012, 18:27 »

Если честно - не представляю, как это организовать.
Алгоритм приблизительно такой:

Код:
MainWindow::StartCalculation() {
  // считывание параметров и т.д.
  thread->start(); //thread типа MyThread унаследованного от QThread
}
MyThread::run()
{
  do
  {
       ladle->Iterate(); // итерации последовательны, т.е. нельзя их параллельно
       // запись результатов в файл, возбуждение сигнала об обновлении прогрессбара...
  }
  while (условие выхода);
}

Ladle::Iterate()
{
   считать_то(); // каждое считать() - это пробег по 3-д массиву
   считать_сё();
   for ( m = 0; m < iterations; m++) // iterations обычно = 500-5000
      считать_еще(); // именно тут я хотел распараллелить, а если получится, то потом в каждом "считать()"
}
Схематически оно выглядит так. Вот куда тогда всовывать это #pragma omp parallel for ? Перед ladle->Iterate(); или thread->start(); ? Так вроде нельзя, там же не циклы...
Извиняюсь, что торможу и нагружаю, просто уже устал Улыбающийся
« Последнее редактирование: Ноябрь 22, 2012, 18:34 от Daniel » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Ноябрь 22, 2012, 19:10 »

Код:
   for ( m = 0; m < iterations; m++) // iterations обычно = 500-5000
      считать_еще(); // именно тут я хотел распараллелить, а если получится, то потом в каждом "считать()"
}
Этот цикл должен быть достаточно трудоемким, если же на его выполнение затрачиваются доли секунды - нет смысла городить огород. Точнее считать_еще() должно быть достаточно трудоемким, просто число итераций ни о чем не говорит, бывает и 10-20 параллелятся прекрасно.

Лучше всего просто перенести все в главную нитку и забыть о MyThread. Если же не хочется "так много ломать", то можно сделать сигнал с BlockingQueuedConnection который остановит MyThread а слот в главной нитке запустит бригаду ниток omp. В любом случае оmp parallel вставлять в главной нитке перед циклом который нужно распараллелить
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.077 секунд. Запросов: 23.