top of page

OpenMP Work Sharring Construct

  • Writer: Sevdanur GENC
    Sevdanur GENC
  • Mar 12, 2013
  • 4 min read

Work Sharing Construct konusu icerisinden 3 yapiyi orneklerle inceliyor olacagiz. Paralel programlama icerisinde Thread'ler arasinda is paylasimlarini yonetebilecegimiz yapilardir. Master thread'inizin paralel havuza girisinde is parcalarina nasil uymasini istiyorsak burada belirleyebiliyoruz. Su ana basliklar altinda inceleyecek olursak; loop, sections ve single ile isimlendirilen directive yapilardir.

              #pragma omp : Bu ifade ile paralel clause yapimiz olusmaktadir. Thread'leri calisma gorevlerine gore ayirabilmemiz icin bu ifadeden sonra Directive'leri belirlememiz gerekmektedir. Hemen ardindan da Clause'unu nitelendiriyoruz.

Loop Directive Yapisi;

Loop Construct isminden de anlasilacagi gibi dongulerle calisiyor olacagiz. Dongulerimizi C++'da calisirken paralel havuz icerisinde directive'ini for olarak isimlendirdikten sonra

#pragma omp for

seklinde cagiriyor olacagiz. Clause yapisina gelince;

              Bu bilgilerin kesinlikle bir sekilde bu kod blogu icerisinde olmasi gerekiyor. Oncelikle #pragma omp parallel yapisi olmali ardindan for ve sections gibi tanimlamalari yapmamiz gerekmektedir.

          Loop yapisini tanimlarken yukaridaki gibi oncelikle parallel yapisi ardindan for yapisini belirlemedende kisa bir yontemle bunu tek bir satirlik kod haline getirebiliriz. Buradaki asil amac ise tamamen hiz'dir.

Loop.Cpp Kaynak Kodu;

#include<iostream> #include<conio.h> #include<omp.h> using namespace std; #define n 10 int main() { int a=5,i=0; int *b=(int*)malloc(n*sizeof(int)); #pragma omp parallel { #pragma omp for for(i=0; i<n; i++) b

=a; } for(int i=0; i<n; i++) cout<<"b:" <<b

<<endl; getche(); return 0; } a degiskenini paralel havuz icerisinde for ile donguye aliyor ve b serisinde isleme sokuyoruz. Ekran ciktisi su sekilde olacaktir;

#pragma omp parallel for ifadesinden sonra clause'larin yer aldigindan bahsetmistik. Bunlara private, shared, schedule, if seklinde ornek verebiliriz. Shared yapisi; paralel bir yapi icerisindeki degiskeni ile tum thread'lere hedef olarak gosterebiliriz. Bu olay sadece okuma islemi yapiyor, yazma islemini gerceklestirmiyor. Bir ram'de bir tane n belirledigimizi dusunursek bellekte herhangi bir yerde butun thread'ler bu n'i gorecek ve tek bir n'i algiliyor olacaklar. #pragma omp parallel for shared (n)   //n degiskenini iceride ki tum thread'ler kullanabilir anlamina gelir.

Private Clause

Paralel yapi icerisindeki her bir thread'e ozel degiskenleri belirlemis oluyoruz. #pragma omp parallel for private (i)   ifadesinde aslinda i'den kac tane varsa o kadar kopyala ve herkes kendi degiskeni ile calissin anlamina gelmektedir. Bir nevi hepsine ozel bir degisken belirlemis oluyoruz. lastprivate; paralel havuz icerisindeki en son degeri paralel disinda da kullanmamiz saglayacak bir clause yapisidir. firstprivate; paralel havuz icerisindeki ilk degeri paralel disinda da kullanmamizi saglayan bir clause yapisidir.

Private.Cpp Kaynak Kodu;

#include<iostream> #include<conio.h> #include<omp.h> using namespace std; #define n 10 int main() { int a=0,i=0; #pragma omp parallel for private(i,a) for(i=0; i<n; i++) { a=i+1; printf("Thread %d has a value of a=%d for i=%d\n",omp_get_thread_num(),a,i); } printf("value a:%d",a); getche(); return 0; } Kodlardanda anlasilacagi gibi, i ve a degiskenlerini private ile ozellestirdikten sonra thread'lerin kendi aralarinda nasil calisarak sonuclarini asagidaki ekran goruntusunde yorumlayabilirsiniz.

Schedule Clasue

Schedule yapida dikkat etmemiz uc type bulunmaktadir. Bunlar static, dinamic ve quided'dir. Schedule'un default degeri aslinda static'tir ve is sayisi / islemci sayisi seklinde lineer bir sekilde calismaktadir. Dezavantaji, diger thread'ler islerini erken bitirdiginde geri kalan islerini gec bitiren thread'ler bulunuyor ve bunlari tespit edemiyoruz. Dinamic type'ini kullanirsak kendimiz is yuklerini belirleyebilmis olucaz. Avantaji, her bir thread'e parca'lari (chunk) kendimiz atamis oluyoruz. Quided ise tum isi islemci sayisina gore boluyor ve parcalari esitliyor. Artan bir is varsa onlari da verdigimiz parca sayisina gore ayiracaktir. Stabil bir sekilde hizlandirmayi algilayabilmemiz zordur.  Kullanimi hakkinda bir kac ornek verecek olursak; #pragma omp parallel for private(i) shared(n) schedule(dynamic,chunk) for (i=0: i<n i++) { c

= a

+ b

; } #pragma omp parallel for private(i) shared(n) schedule(static,chunk) for (i=0: i<n i++) { c

= a

+ b

; } #pragma omp parallel for private(i) shared(n) schedule(quided,chunk) for (i=0: i<n i++) { c

= a

+ b

; }

Sections Directive Yapisi;

Sections ismindende anlasilacagi gibi paralel havuz icerisinde her bir thread'e is yuku ayrimi, is paylasimi veya diger bir ifade ile is atamasi yapiyor olacagiz. Her bir thread'e belirleyecegimiz is yukleri icinde yine kod yapisi icerisinde bunlari ayri ayri aliyor olacagiz. Kullanimi; #pragma omp sections { #pragma omp section .. #pragma omp section .. #pragma omp section .. }

Sections.Cpp Kaynak Kodu;

#include<iostream> #include<conio.h> #include<omp.h> using namespace std; void funcA() { cout<<"This section is executed by thread "<<omp_get_thread_num()<<endl; } void funcB() { cout<<"This section is executed by thread "<<omp_get_thread_num()<<endl; } int main() { #pragma omp parallel { #pragma omp sections { #pragma omp section funcA(); #pragma omp section funcB(); } } getche(); return 0; } Kod incelendiginde paralel havuz icerisinde iki tane sections belirlenmistir. Bunlardan birisi A fonksiyonunu digeri ise B fonksiyonu uzerinde calismak icin gorevlendirilmistir. Seri olarak calistirildiginda haliyle her iki fonksiyonda tek bir thread'de calisiyor olacakken paralel calistirdigimizda ornegin 0. ve 1. thread'lerin sirayla calistigini goreceksiniz. Yuk dengeleme islemini hesaplarkende aslinda bunun bir dezavantaj oldugunu calismalarinizda karsilasiyor olacaksiniz.



Single Directive Yapisi;

Single isminden de anlasilacagi gibi sadece bir tane thread'in belirlemis oldugumuz isi yapmasini istiyoruz. Diger thread'ler ise kendilerine verilmis olan gorevleri bu tek thread'den bagimsiz bir sekilde islerini yapacaklardir. Burada aslinda gizli bir barrier vardir ki bu da implicit barrier olarak isimlendirilir. No wait clause ile senkronizasyon olaylarini sonlandirabiliriz. Ayrica reduction islemleri bulunmaktadir, tum degerleri en son da bir global degiskene atamaktadir. Kullanim sekli;

Single.Cpp Kaynak Kodu;

#include<iostream> #include<conio.h> #include<omp.h> using namespace std; #define n 10 int main() { int a=5,i=0; int *b=(int*)malloc(n*sizeof(int)); #pragma omp parallel shared(a,b) private(i) { #pragma omp single { a=10; cout<<"single construct executed by thread"<<omp_get_thread_num()<<endl; } #pragma omp for for(i=0; i<n; i++) b

=a; } for(int i=0; i<n; i++) cout<<"b:" <<b

<<endl; getche(); return 0; } Simdi buradaki kod yapisini inceleyecek olursak; a=10 degiskeni ile thread'in herhangi bir tanesini a=10 seklinde atamis oluyoruz. Single yapi, thread 0 tarafindan calistiriliyor. a degerini 10 yaptiktan sonra b degeri asagidaki kod bloglarindan artik hep 10 degerini alacaktir. a'nin son degerini b'ye transfer etmis oluyor. Yani o thread oraya girdigi anda ayni anda hepsi 10 degerini kabulleniyor. Parallel 'in disarisina cikarildigi zaman a'ya hic bir zaman erisemiyoruz. a'nin degeri seri kod halindeyken 5, paralel kod halindeyken 10'dur. Lastprivate diye bir clause kullanacak olursam eger, paralel kodlar icerisindeki a'nin yapisi degistiginde programin butun asamalarinda paralel'deki kullanildigi gibi kullanilmaktadir.Thread'lerin burada bir tanesi isliyor geri kalanlar bekliyor. Thread'lerin hepsinin senkronizasyona ugramasi gerekmektedir. Boylelikle 10'u da aktif hale gelmektedir. Ekran goruntusu ise asagidaki gibidir.

Recent Posts

See All
Oracle Java Cloud Service Uygulamasi

Bir onceki Oracle Cloud Computing yazisinda bahsettigim gibi JDeveloper Oracle Cloud icin gelistirmis oldugu surumu olan Oracle JDeveloper 11g (11.1.1.6.0) ile kucuk bir uygulama gelistirip bunu oracl

 
 
 
Oracle Cloud Computing Hakkinda

Bulut bilisim konusundaki arastirmalarima devam ederken bu kez solugu Oracle Cloud Computing'de aldim. Bu makalem ve ilerleyen makalelerimde Trial versiyonu ile user tarafini pek yormayan bir yapidan

 
 
 
Loop Optimization - Loop Optimizasyonu

Var olan dongulerin acilmis yada sikistirilmis hallerini optimize ettikten sonra cache'imizde nasil bir performans saglayacigini gorebiliriz. Bunun icin uc adet dogu optimizasyon yontemi bulunmaktadir

 
 
 

Comments


©2035 by Sevdanur Genc. Powered and secured by Wix

bottom of page