Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Циклы For и OpenMP, Последовательный вывод 
:(
    Опции темы
BrookBond
Дата 12.6.2013, 10:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Приветствую знатоков!

Только начал изучать OpenMP и сразу попытался применить его на практике.
Пишу прогу, которая в дальнейшем будет работать (сравнивать матрицы больших размеров) на многоядерном компе. 
Вот проблемная часть этой проги, где используется OpenMP и возникают непонятные мне действия. 
Код:

Код

#pragma omp parallel for
for(p=0;p<=6300;p++) {

Sp1x=(Sp1.X*Sp1.s+Sp1.R*pow(fi,a/(2*pi))*cos(Sp1.c*a+Sp1.faz))/Sp1.s;//-3*cos(a-faz);
Sp1y=Sp1.y0+Sp1.R*pow(fi,a/(2*pi))*sin(Sp1.c*a+Sp1.faz);//-3*sin(a-faz);
if(a>=0 && a<=2*pi){i1=1;}
if(a>2*pi && a<=4*pi){i1=2;}
if(a>4*pi && a<=6*pi){i1=3;}
if(a>6*pi && a<=8*pi){i1=4;}

    if(Sp1x>XX1+2)  {
     b=0;

     do {
     Sp2x=(Sp2.X*Sp2.s+Sp2.R*pow(fi,b/(2*pi))*cos(Sp2.c*b+Sp2.faz))/Sp2.s;//-3*cos(a-faz);
     Sp2y=Sp2.y0+Sp2.R*pow(fi,b/(2*pi))*sin(Sp2.c*b+Sp2.faz);//-3*sin(a-faz);
     if(b>=0 && b<=2*pi){i2=1;}
     if(b>2*pi && b<=4*pi){i2=2;}
     if(b>4*pi && b<=6*pi){i2=3;}
     if(b>6*pi && b<=8*pi){i2=4;}

         if(Sp2x>XX2+1)  {
     if(Sp1x-0.1<=Sp2x && Sp1x+0.1>=Sp2x && Sp1y-2.5<=Sp2y && Sp1y+2.5>=Sp2y )
                        { //fprintf(f5,"%1.2f \t %1.2f \t%d \t%d\n",Obmen1.x,Obmen1.y,Obmen1.n,Obmen2.n);
                          Obmen3[j].x=Sp1x; Obmen3[j].y=Sp1y; Obmen3[j].n=i1; Obmen3[j].X0=Sp1.X; Obmen3[j].X1=Sp1.X1;
                          Obmen3[j+1].x=Sp2x; Obmen3[j+1].y=Sp2y; Obmen3[j+1].n=i2; Obmen3[j+1].X0=Sp1.X; Obmen3[j+1].X1=Sp1.X1;
        printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j].x,Obmen3[j].y,Obmen3[j].n,Obmen3[j].X0,Obmen3[j].X1,p);
// в самом правом столбце выводятся значения внешнего цикла по p                                  
 j=j+2;
                           break;}
                          }
     b+=0.004;
           } while (b<=25.2);
           } //if(Sp1x>Sp1.X1)

a=0.004*p;
}


Проблема в том, что если внешний цикл по р запараллелить, то данные начинают смешиваться, выводятся хаотично так как показано на прикрепленном рисунке (самый правый столбец это значения внешнего цикла по р). А нужно чтобы они выводились последовательно, с начала то что считает первое ядро (0...3150), а затем второе (3151..6300), но чтоб считались параллельно. Подскажите пожалуйста, что добавить/убрать ?
Прикреплен проект в Qt Creator, работаю на вин 7.

Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  Program.rar 321,51 Kb
PM MAIL WWW   Вверх
BrookBond
Дата 12.6.2013, 10:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Вот скрин работы проги

Присоединённый файл ( Кол-во скачиваний: 12 )
Присоединённый файл  Результат_работы_проги.png 34,32 Kb
PM MAIL WWW   Вверх
Фантом
Дата 12.6.2013, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вы это прекратите!
***


Профиль
Группа: Участник Клуба
Сообщений: 1516
Регистрация: 23.3.2008

Репутация: нет
Всего: 49



Цитата(BrookBond @  12.6.2013,  11:05 Найти цитируемый пост)

Проблема в том, что если внешний цикл по р запараллелить, то данные начинают смешиваться, выводятся хаотично так как показано на прикрепленном рисунке (самый правый столбец это значения внешнего цикла по р). А нужно чтобы они выводились последовательно, с начала то что считает первое ядро (0...3150), а затем второе (3151..6300), но чтоб считались параллельно.

Поскольку Вы используете параллельный цикл, то не можете (и не должны) предсказать, какая из итераций когда будет выполняться. Поэтому, если вывод нужен в строго определенном порядке, то надо сохранять где-то результаты счета, а уже потом в обычном последовательном цикле выполнять вывод результатов. Кстати, и с точки зрения итогового быстродействия это тоже разумнее.
PM   Вверх
BrookBond
Дата 12.6.2013, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Спасибо, сейчас как раз над этим работаю
PM MAIL WWW   Вверх
Wuffur
Дата 18.6.2013, 16:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



По-моему надо просто написать:
 
Код

  # pragma omp barrier

Перед printf.

А нет я не прав, надо еще один for запилить.

Это сообщение отредактировал(а) Wuffur - 18.6.2013, 21:15
PM MAIL ICQ   Вверх
BrookBond
Дата 18.6.2013, 22:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Подскажите если знаете, вот такая проблема получается если использовать прагму. Первое ядро в цикле по р считает элементы от 0 до 3150, а второе 3151 - 6300.  Но довольно часто получается, что второе ядро быстрее считает свою часть и в то время как первое ядро считает  i-й элемент (внешний цикл) второе считает уже i+1 элемент и соответственно получается путаница в данных.
Как сделать так чтобы второе ядро ждало завершения счета первого ядра и потом уже они вместе переходили бы на i+1 элемент?  

Код


for(i=0;i<=ab1;i++)//ab1
    {    // printf("%d\n",i);
   
 
#pragma omp parallel for num_threads(2)
for(p=0;p<=6300;p++) {

// кусок кода, здесь идет перебор и сравнение больших матриц

Sp1x=(Sp1.X*Sp1.s+Sp1.R*pow(fi,a/(2*pi))*cos(Sp1.c*a+Sp1.faz))/Sp1.s;//-3*cos(a-faz);
Sp1y=Sp1.y0+Sp1.R*pow(fi,a/(2*pi))*sin(Sp1.c*a+Sp1.faz);//-3*sin(a-faz);
if(a>=0 && a<=2*pi){i1=1;}
if(a>2*pi && a<=4*pi){i1=2;}
if(a>4*pi && a<=6*pi){i1=3;}
if(a>6*pi && a<=8*pi){i1=4;}
}




PM MAIL WWW   Вверх
Wuffur
Дата 18.6.2013, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



Как вариант сначала можно записать в массив, а потом в файл. То есть через указатели.

Ждать пока ядра завершаться:
Код

#pragma omp barrier

я уже сказал.

Мне тут нравится документация:
IBM Linux OMP public documentation

И у меня это код на linux`е segfault`ится.

Вот ещё, вроде можно с :
Код

#pragma omp critical

Так даже в том коде работать должно.

StackOverflow - is there an implicit barrier after omp critical section?
MSDN Pragma OMP Critical

Это сообщение отредактировал(а) Wuffur - 18.6.2013, 23:45
PM MAIL ICQ   Вверх
BrookBond
Дата 19.6.2013, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Цитата(Wuffur @  18.6.2013,  23:20 Найти цитируемый пост)
код C++
1:
#pragma omp barrier

я уже сказал.

Мне тут нравится документация:
IBM Linux OMP public documentation


Подскажи пожалуйста код, а то никак не могу разобраться с барьером
Код

for(i=0;i<=ab1;i++) {

#pragma omp parallel for
for(p=0;p<=6300;p++) {

Sp1x=(Sp1.X*Sp1.s+Sp1.R*pow(fi,a/(2*pi))*cos(Sp1.c*a+Sp1.faz))/Sp1.s;//-3*cos(a-faz);
Sp1y=Sp1.y0+Sp1.R*pow(fi,a/(2*pi))*sin(Sp1.c*a+Sp1.faz);//-3*sin(a-faz);
if(a>=0 && a<=2*pi){i1=1;}
if(a>2*pi && a<=4*pi){i1=2;}
if(a>4*pi && a<=6*pi){i1=3;}
if(a>6*pi && a<=8*pi){i1=4;}

    if(Sp1x>XX1+2)  {
     b=0;

     do { 

     Sp2x=(Sp2.X*Sp2.s+Sp2.R*pow(fi,b/(2*pi))*cos(Sp2.c*b+Sp2.faz))/Sp2.s;//-3*cos(a-faz);
     Sp2y=Sp2.y0+Sp2.R*pow(fi,b/(2*pi))*sin(Sp2.c*b+Sp2.faz);//-3*sin(a-faz);
     if(b>=0 && b<=2*pi){i2=1;}
     if(b>2*pi && b<=4*pi){i2=2;}
     if(b>4*pi && b<=6*pi){i2=3;}
     if(b>6*pi && b<=8*pi){i2=4;}

         if(Sp2x>XX2+1)  {
     if(Sp1x-0.1<=Sp2x && Sp1x+0.1>=Sp2x && Sp1y-2.5<=Sp2y && Sp1y+2.5>=Sp2y )
                        { //fprintf(f5,"%1.2f \t %1.2f \t%d \t%d\n",Obmen1.x,Obmen1.y,Obmen1.n,Obmen2.n);
            Obmen3[j].x=Sp1x; Obmen3[j].y=Sp1y; Obmen3[j].n=i1; Obmen3[j].X0=Sp1.X; Obmen3[j].X1=Sp1.X1; Obmen3[j].p=p;
            Obmen3[j+1].x=Sp2x; Obmen3[j+1].y=Sp2y; Obmen3[j+1].n=i2; Obmen3[j+1].X0=Sp1.X; Obmen3[j+1].X1=Sp1.X1;Obmen3[j+1].p=p;
        printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j].x,Obmen3[j].y,Obmen3[j].n,Obmen3[j].X0,Obmen3[j].X1,Obmen3[j].p);
        printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j+1].x,Obmen3[j+1].y,Obmen3[j+1].n,Obmen3[j+1].X0,Obmen3[j+1].X1,p);
                           j=j+2;
                           break;}
                          }
     b+=0.004;
           } while (b<=25.2);
           } //if(Sp1x>Sp1.X1)

if (p==3150 || p==6300) {
 #pragma omp barrier
 }


a=0.004*p;
  



     } // конец цикла по i



При такой записи барьера результата нет, по прежнему идет перескок одного ядра на i+1 элемент, куда его поставить?
PM MAIL WWW   Вверх
Wuffur
Дата 19.6.2013, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



Да , потому что потоки выполняются параллельно до барьера, синхронизируются и дальше выполняются параллельно, поэтому и перескакивает. Если выполняется дериктива #pragma omp critical, то компилятору говорится, что в этом участке кода нужно выполнять в один поток. Вся магия.

То есть если printf запихнуть в 
Код

...
#pragma omp critical {
printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j].x,Obmen3[j].y,Obmen3[j].n,Obmen3[j].X0,Obmen3[j].X1,Obmen3[j].p);
        printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j+1].x,Obmen3[j+1].y,Obmen3[j+1].n,Obmen3[j+1].X0,Obmen3[j+1].X1,p);
}
...

то всё должно быть нормально.

Что происходит когда ставишь барьерную синхронизацию на 3150 элементе?

Наверное программа распараллеливает for между задачи между ядрами - один выполняет от 1 до 1575 другой от 1576 до 3150, а после от 3151 до 4725 и от 4726 до 6300. 
В таком случае на 6300-ом элементе её ставить нет смысла.

Барьерная синхронизация нужна бы была, если бы у вас элементы в printf() передавались бы переменные из других значений итератора цикла for и у вас выводились еще неинициализированные на каких-то шагах итерации значения переменных. Но это совершенно не влияет на порядок их вывода на стандартный поток.

Без барьерной синхронизации всё не так однозначно,  порядок выполнение параллельных команд может зависеть от состояния кэша и каких-то физических факторов, к примеру температуры процессора.
Вывод сначала в массив был лучше просто вывода в файл или стандартный поток тем, что можно было бы записать произвольно, а в файл(хотя конечно можно и произвольно с fseek, fwrite) и в стандартный поток записывается по порядку.

Это сообщение отредактировал(а) Wuffur - 19.6.2013, 14:21
PM MAIL ICQ   Вверх
BrookBond
Дата 19.6.2013, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Цитата(Wuffur @  19.6.2013,  13:57 Найти цитируемый пост)
Что происходит когда ставишь барьерную синхронизацию на 3150 элементе?


Получается что прога зависает (останавливается).


Цитата(Wuffur @  19.6.2013,  13:57 Найти цитируемый пост)
Наверное программа распараллеливает for между задачи между ядрами - один выполняет от 1 до 1575 другой от 1576 до 3150, а после от 3151 до 4725 и от 4726 до 6300. 


На это не похоже.

попробовал сделать так
Код

#pragma omp critical {
Obmen3[j].x=Sp1x; Obmen3[j].y=Sp1y; Obmen3[j].n=i1; Obmen3[j].X0=Sp1.X; Obmen3[j].X1=Sp1.X1; Obmen3[j].p=p;
            Obmen3[j+1].x=Sp2x; Obmen3[j+1].y=Sp2y; Obmen3[j+1].n=i2; Obmen3[j+1].X0=Sp1.X; Obmen3[j+1].X1=Sp1.X1;Obmen3[j+1].p=p;
        printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j].x,Obmen3[j].y,Obmen3[j].n,Obmen3[j].X0,Obmen3[j].X1,Obmen3[j].p);
        printf("%1.2f \t%1.2f \t%d \t%d \t%d \t%d \n",Obmen3[j+1].x,Obmen3[j+1].y,Obmen3[j+1].n,Obmen3[j+1].X0,Obmen3[j+1].X1,p);
                           j=j+2;
}


Становится гораздо лучше, данные выводит почти что верно, но я использую printf лишь для того чтоб отслеживать какие значения записываются в Obmen3 . А при такой записи все равно в Obmen3 записываются не по порядку, а нужно чтобы в этот массив записывались данные в том же порядке как и при работе на одном ядре.   Help.... smile  
PM MAIL WWW   Вверх
Wuffur
Дата 19.6.2013, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



А почему бы вам в массив не писать?
То есть я не совсем понимаю, что там инициализировалось:
Код


struct Obmen1 *Obmen3= new struct Obmen1 [N];


Дебагер вам в руки.

Это сообщение отредактировал(а) Wuffur - 19.6.2013, 15:17
PM MAIL ICQ   Вверх
BrookBond
Дата 19.6.2013, 15:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Возможно все.....



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 9.6.2012
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Цитата(Wuffur @  19.6.2013,  15:12 Найти цитируемый пост)
А почему бы вам в массив не писать? 


Так я же и записываю все данные сравнения в массив структур Obmen3, или что то не так делаю?
PM MAIL WWW   Вверх
Wuffur
Дата 19.6.2013, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



Попробуйте раскомментить второй printf и проверить выполняются ли условия выражения if, если да, то проблема не внутри скобок.

Не знаю, может барьерная синхронизация перед критической секцией поможет, но мне кажется вряд ли.

У меня ваша программа даже под 10-ой студией не запускается.

Это сообщение отредактировал(а) Wuffur - 19.6.2013, 15:48
PM MAIL ICQ   Вверх
Wuffur
Дата 19.6.2013, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



Цитата(BrookBond @  19.6.2013,  14:45 Найти цитируемый пост)
Становится гораздо лучше, данные выводит почти что верно, но я использую printf лишь для того чтоб отслеживать какие значения записываются в Obmen3 . А при такой записи все равно в Obmen3 записываются не по порядку, а нужно чтобы в этот массив записывались данные в том же порядке как и при работе на одном ядре.   Help.... smile   

Ну так printf пишет в стандартный поток, сделайте fprintf в критической секции будет писать в файл.

PM MAIL ICQ   Вверх
Wuffur
Дата 13.7.2013, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 45
Регистрация: 22.7.2007

Репутация: нет
Всего: нет



Попробуйте еще #pragma omp single вначале, чтобы одна нить исполняла одну секцию кода и #pragma omp barrier #pragma omp master перед файловым выводом.
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0932 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.