الجلسة الثانية - Eng . Rami Mahfoud

Download Report

Transcript الجلسة الثانية - Eng . Rami Mahfoud

‫البرمجة التفرعية‬
‫الجلسة الثانية‬
‫‪Eng. rami mahfoud http://irami.im‬‬
‫•‬
‫•‬
‫العملية ( ‪ )process‬هي برنامج يقوم بانجاز مهمة ( ‪ ) task‬على المعالج‬
‫كل معالج في نظام تبادل الرسائل يقوم بتشتغيل نسخة من البرنامج ‪instance/copy of a program‬‬
‫بحيث ‪:‬‬
‫–‬
‫–‬
‫–‬
‫•‬
‫•‬
‫•‬
‫•‬
‫تكون مكتوبة بواسطة لغة متسلسلسة ‪ .‬مثل ‪c++‬‬
‫غاليا ما يكون برنامج وحيد يتم تطبيقه على مجموعات متعددة من البيانات‬
‫المتحوالت في كل برنامج فرعي تحوي ‪:‬‬
‫نفس أسماء المتحوالت‬
‫لكن أماكن تواجدها مختلفة ( ذواكر موزعة ) وبيانات مختلفة‬
‫ كل المتحوالت تكون محلية بالنسبلة للعملية ‪.‬‬‫يتم التراسل بواسطة إجراءات (‪ ) routines‬إرسال واستقبال تسمى تبادل الرسائل‬
‫‪data‬‬
‫‪program‬‬
‫‪communication network‬‬
‫‪MPI Course‬‬
‫‪2‬‬
‫توزيع العمل والبيانات‬
‫( معرفات للتواصل فيما بنيها‬mpi-processes ( mpi ‫• تحتاج عمليات ال‬
rank = identifying number
‫ العملية‬rank ) ‫• كل عمليات التوزيع تعتمد على ) رتبة‬
myrank=0
myrank=1
myrank=2
myrank=
(size-1)
data
data
data
data
program
3
program
program
communication
network
MPI Course
program
SPMD
Single Program, Multiple Data •
Same (sub-)program runs on each processor •
MPI allows also MPMD, i.e., Multiple Program, ... •
MPMD can be emulated with SPMD –
4
Emulation of MPMD
• main(int argc, char **argv){
if (myrank < .... /* process should run the ocean model */){
ocean( /* arguments */ );
}else{
weather( /* arguments */ );
}
}
5
‫مبادئ ال ‪MPI‬‬
‫• تتكون ال ‪ MPI‬من ‪ 128‬تابع ولكن فعليا هناك ‪ 6‬توابع يمكن عن‬
‫طريقها حل معظم المسائل التفرعية وهي ‪:‬‬
‫‪MPI_Init‬‬
‫‪MPI_Comm_size‬‬
‫‪MPI_Comm_rank‬‬
‫‪MPI_Send‬‬
‫‪MPI_Recv‬‬
‫‪MPI_Finalize‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫‪6‬‬
MPI ‫مثال عن بنية البرنامج في بيئة‬
‫ ورقمها‬Hello World ‫ برنامج تقوم فيه كل عملية بطباعة‬: ‫لنأخذ أبسط مثال‬
#include<iostream>
#include<mpi.h>
using namespace std;
void main(int argc, char** argv)
{
int mynode,totalnodes;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&totalnodes);
MPI_Comm_rank(MPI_COMM_WORLD,&mynode);
cout<<"HELLO WORLD FROM PROCESS "<<mynode;
cout<<" of "<<totalnodes<<endl;
system("pause");
MPI_Finalize();
}
•
‫• التعليمة األولى تقوم بتضمين الملف الرأسي الخاص بالدخل‬
‫والخرج‪Input/Output Stream‬‬
‫• التعليمة الثانية تقوم بتضمين الملف الرأسي الحاوي على روتينات المعيار ‪.MPI‬‬
‫• التعليمة الثالثة تقوم بتضمين فضاء األسماء ‪ std‬ضمن البرنامج‪ ،‬وبذلك نختصر‬
‫في الكتابة فعوضا ً عن كتابة‪:‬‬
‫"‪ Std::cout<<"someWords‬نكتب هذه التعليمة‪ ،‬عند استخدام فضاء األسماء‬
‫‪ ،std‬بالشكل‪:‬‬
‫;"‪cout<<"someWords‬‬
‫• في السطر الرابع لدينا الـ ‪ ،main‬وكما نعلم في ‪ C++‬الـ ‪ main‬هو تابع‬
‫والـ ‪ arguments‬داخل قوسيه هي المتحوالت الممررة له من برنامج آخر‪ ،‬غالبا ً‬
‫يكون البرنامج اآلخر هو الـ ‪( system shell‬مثل ‪ cmd‬في ‪:)Windows‬‬
‫• ‪ :int argc‬اختصار لـ ‪ ،Argument Count‬وهو عدد األشياء الممررة إلى‬
‫البرنامج‪.‬‬
‫• ][‪ :char **argv or char *argv‬اختصار لـ‪ ،Argument Vector‬وهي‬
‫مصفوفة عناصرها من النوع مؤشر إلى محرف‪ ،‬تُستخدم لتخزين األشياء التي‬
‫ستمرر إلى البرنامج‪.‬‬
‫•‬
‫اإلجراء ‪: MPI_Init‬يجب استدعاءه قبل استدعاء أي إجراء آخر من مكتبة ‪ MPI‬ألنه‬
‫المسؤول عن تهيئة بيئة ‪ MPI‬للعمل‪ ،‬في نهاية تنفيذ هذا اإلجراء في الذاكرة سيتم نسخ قائمة‬
‫الوسطاء الممررة للبرنامج‪ ،‬وهنا يجب مالحظة أن النسخ ليس ضروري تبعا ً للمعيار ‪ ،MPI‬لكنه‬
‫مجرد توسيع لتحقيق إمكانية توزيع المتحوالت الممررة للبرنامج إلى جميع العمليات التي تنفذ‬
‫ّ‬
‫على اآلالت المختلفة‪ .‬لكننا ال نترك القوسين في اإلجراء السابق فارغين حيث سيسبب ذلك خطأ‬
‫ترجمة‪.‬‬
‫•‬
‫توضيح‪ :‬يمكننا كتابة الكود التالي‪:‬‬
‫;‪char ** b‬‬
‫;‪int a‬‬
‫;)‪MPI_Init(&a,&b‬‬
‫• ومن الجدير بالذكر أن بيئة ‪ MPI‬ال ترى من البرنامج إال ما هو محصور بين اإلجرائين‪:‬‬
‫)‪ MPI_Init(&argc,&argv‬و )(‪.MPI_Finalize‬‬
‫• اإلجراء ‪ : MPI_Comm_Size‬يحدد عدد العمليات التي تنفذ في الـ‬
‫‪( communicator‬الـ ‪ communicator‬هونظام اتصال مثل الـ‬
‫‪ ،mail system, phone system‬وكل رسالة تمر عبر مكالمة في‬
‫النظام لديها متحول من النوع ‪ ،communicator‬والـ‬
‫‪ communicator‬االفتراضي هو الـ ‪MPI_COMM_WORLD‬‬
‫الذي ينشأ بواسطة اإلجراء ‪ MPI_Init‬وهو يضم جميع العمليات‪،‬‬
‫سنوضح ذلك الحقا ً)‪.‬‬
‫• اإلجراء ‪ MPI_Comm_size‬له الشكل التالي ‪:‬‬
‫(‪MPI_Comm_size‬‬
‫‪MPI_Comm comm, /* in */‬‬
‫‪int *size‬‬
‫‪/*out*/‬‬
‫)‬
‫• حيث ‪ comm‬هو غرض من ‪ MPI_Comm‬الذي يمثل ال‬
‫‪ communitcation‬الحالي و ‪size‬هو مؤشر إلى قيمة صحيحة‬
‫تمثل عدد اإلجرائيات الكلي‬
‫• اإلجراء ‪ MPI_Comm_rank‬يحدد رقم العملية المستدعاة‬
‫حالياً‪ ،‬وهو رقم نسبي للعملية بين مجموعة العمليات‪.‬‬
‫• وله الشكل التالي ‪:‬‬
‫(‪MPI_Comm_rank‬‬
‫‪MPI_Comm comm, /* in */‬‬
‫‪int *rank‬‬
‫‪/*out */‬‬
‫)‬
‫• حيث ‪ comm‬هو غرض من ‪ MPI_Comm‬الذي يمثل ال‬
‫‪ communitcation‬الحالي و ‪ rank‬هو مؤشر إلى قيمة‬
‫صحيحة تمثل رتبة ( ‪ ) rank‬اإلجرائية ( ‪)process‬‬
‫• اإلجراء ‪ MPI_Finalize‬يُستدعى عند انتهاء تنفيذ العمليات‬
‫كلها‪ ،‬ويسبب انتهاء عمل بيئة ‪ ،MPI‬لكنه ال يسبب توقيف‬
‫العمليات التي ال تزال في التنفيذ‪ ،‬وإنما ينتظر انتهاء تنفيذها (حيث‬
‫يوجد إجراء آخر يقوم بإحباط تنفيذ كل العمليات حتى التي ال تزال‬
‫في التنفيذ هو ‪)MPI_Abort‬‬
‫• كل عملية من العمليات (المحدد عددها سابقا ً) تبدأ بالتنفيذ بشكل‬
‫مستقل عن األخريات بدءا ً من التعليمة ‪ MPI_Init‬وحتى‬
‫التعليمة ‪.MPI_Finalize‬‬
‫• ;)"‪ system("pause‬هي تعليمية ال دخل لها بال ‪ mpi‬وتوضع‬
‫فقط للمحافظ على نوافذ التنفيذ حتى ال تختفي بمجرد انتهاء التنفيذ‬
‫يمكن االستعاضة عنها بوضع ‪ Break Point‬مكانها‬
‫•‬
‫تنفيذ البرنامج بواسطة ‪mpiexec‬‬
‫يتم تشغيل ال ‪ cmd‬والذهاب لمجلد الملف التنفيذي للبرنامج‬
‫وكتابة التعليمة التالية‬
‫‪mpiexec –n ProcessNumber ProjectName‬‬
‫حيث‬
‫‪ : ProcessNumber‬تمثل عدد المعالجات‬
‫‪ : ProjectName‬اسم المشروع ( اسم الملف التنفيذي )‬
‫تراسل المعطيات في ‪MPI‬‬
‫• يعد إرسال واستقبال الرسائل تقنية االتصال األساسية في‬
‫‪ ،MPI‬عمليتي االتصال األساسيتين من النوع ‪point-to-‬‬
‫‪ point‬هما ‪ send‬و ‪: receive‬‬
‫تراسل المعطيات في ‪MPI‬‬
‫( ‪MPI_Send‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫‪message‬‬
‫‪count‬‬
‫‪datatype‬‬
‫‪dest‬‬
‫‪tag‬‬
‫‪comm‬‬
‫* ‪void‬‬
‫‪int‬‬
‫‪MPI_Datatype‬‬
‫‪int‬‬
‫‪int‬‬
‫‪MPI_Comm‬‬
‫)‬
‫‪ :message‬المتحول الموجود في ذاكرة العملية المرسلة وهو فعليا موقع في الذاكرة يشير إلى موقع بداية‬
‫العناصر المرسلة‬
‫‪ :count‬عدد عناصر الرسالة‪.‬‬
‫‪ :datatype‬أنواع المعطيات للعناصر المرسلة وهو من النمط ‪ MPI_Datatype‬الذي سيتم شرحه‬
‫‪ :dest‬رتبة اإلجرائية المستقبلة‪.‬‬
‫‪ :tag‬الحقة الرسالة‪ ،‬يبين بعض المعلومات عنها‪.‬‬
‫‪ :comm‬يحدد مجال االتصال‪.‬‬
‫تراسل المعطيات في ‪MPI‬‬
‫(‪MPI_Recv‬‬
‫‪/*out*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*in*/‬‬
‫‪/*out*/‬‬
‫‪message‬‬
‫‪count‬‬
‫‪datatype‬‬
‫‪source‬‬
‫‪tag‬‬
‫‪comm‬‬
‫‪status‬‬
‫* ‪void‬‬
‫‪int‬‬
‫‪MPI_Datatype‬‬
‫‪int‬‬
‫‪int‬‬
‫‪MPI_Comm‬‬
‫* ‪MPI_Status‬‬
‫)‬
‫• ‪ :message‬المتحول الموجود في ذاكرة العملية المستقبلة وهو فعليا موقع في الذاكرة يشير إلى موقع بداية العناصر المستقبلة‬
‫والموجودة في الذاكرة المؤقتة ‪buffer‬‬
‫• ‪ :count‬عدد عناصر المستقبلة‪.‬‬
‫• ‪ :datatype‬أنواع المعطيات للعناصر المستقبلة وهو من النمط ‪ MPI_Datatype‬الذي سيتم شرحه‬
‫• ‪ :source‬رتبة اإلجرائية المرسلة‪.‬‬
‫• ‪ :tag‬الحقة الرسالة‪ ،‬يبين بعض المعلومات عنها‪.‬‬
‫• ‪ :comm‬يحدد مجال االتصال‪.‬‬
‫‪ :status‬يعطي حالة الرسالة المستقبلة وهو عبارة عن سجل يحوي الحقول التالية ‪:‬‬
‫‪count‬‬
‫‪cancelled‬‬
‫‪MPI_SOURCE‬‬
‫‪MPI_TAG‬‬
‫‪MPI_ERROR‬‬
‫‪int‬‬
‫‪int‬‬
‫‪int‬‬
‫‪int‬‬
‫‪int‬‬
MPI ‫أنواع البيانات القياسية في‬
C++ ‫ باإلضافة إلى أنواع جديدة غير موجودة في‬،MPI ‫مقابل في‬C++ ‫لكل نوع من أنواع البيانات في‬
‫ والسبب هو أنه قد نوزع البرنامج على معالجات يكون‬.)MPI_PACKED ‫ و‬MPI_BYTE ‫(مثل‬
.MPI ‫ ومقابالتها في‬C++ ‫تمثيل األنماط فيه مختلف الجدول التالي يوضح أنواع البيانات في‬
MPI ‫أنواع البيانات في‬
C++ ‫أنواع البيانات في‬
MPI_CHAR
MPI_SHORT
MPI_INT
MPI_LONG
MPI_UNSIGNED_CHAR
MPI_UNSIGNED_SHORT
MPI_UNSIGNED
MPI_UNSIGNED_LONG
MPI_FLOAT
MPI_DOUBLE
MPI_LONG_DOUBLE
MPI_BYTE
MPI_PACKED
signed char
signed short int
signed int
signed long int
unsigned char
unsigned short int
unsigned int
unsigned long int
float
double
long double
•
---------
: ‫ قم بزيارة الرابط التالي‬vs 2010 ‫ ضمن‬c++ ‫لمعرفة حجم األنماط في‬
•
http://msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.100).aspx
•
‫ إرسال رسالة بين عمليتين‬: ‫مثال‬
#include<mpi.h>
#include<iostream>
using namespace std;
void main( int argc, char ** argv )
{
char message[20];
int myrank;
MPI_Status status;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &myrank );
if (myrank == 0) //code for process zero
{
strcpy(message,"Hello, there");
MPI_Send(message, strlen(message)+1, MPI_CHAR, 1, 99, MPI_COMM_WORLD);
}
else if (myrank == 1) //code for process one
{
MPI_Recv(message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status);
cout<<"recieved: "<<message<<" From Process:"<<status.MPI_SOURCE<<endl;
cout<<"data size:"<<status.count;
}
MPI_Finalize();
}
‫مثال – جمع األعداد‬
‫ إلى‬1 ‫• لنفرض أننا نريد كتابة برنامج يقوم بجمع األعداد من‬
‫ البرنامج التسلسي يكون‬1000
#include<iostream>
using namespace std;
int main(int argc, char ** argv){
int sum;
sum = 0;
for(int i=1;i<=1000;i=i+1)
sum = sum + i;
cout<< "The sum from 1 to 1000 is: " << sum << endl;
}
: ‫البرنامج التفرعي يكون‬
#include<iostream>
#include<mpi.h>
using namespace std;
int main(int argc, char** argv){
int mynode, totalnodes;
int sum,startval,endval,accum;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,
&totalnodes); // get totalnodes
MPI_Comm_rank(MPI_COMM_WORLD,
&mynode);
// get mynode
sum = 0; // zero sum for accumulation
startval = 1000*mynode/totalnodes+1;
endval =1000*(mynode+1)/totalnodes;
for(int i=startval;i<=endval;i++)
sum = sum + i;
if(mynode!=0)
MPI_Send(&sum,1,MPI_INT,0,1,MPI_COMM_WORLD);
else
for(int j=1;j<totalnodes;j++){
MPI_Recv(&accum,1,MPI_INT,j,1,MPI_COMM_WORLD, &status);
sum = sum + accum;
}
if(mynode == 0)
cout << "The sum from 1 to 1000 is: " << sum << endl;
system("pause");
MPI_Finalize();
}
‫تمرين‬
‫• اكتب برنامج تفرعي يقوم بحساب األعداد األولية بين‬
‫‪ 100000000‬و ‪ 400000000‬وكل عملية تقوم بطباعة‬
‫األرقام األولية التي تجدها ‪.‬‬
‫حل التمرين‬
#include<iostream>
#include<mpi.h>
using namespace std;
int main(int argc, char** argv){
int mynode, totalnodes;
int x=100000000;
int y=400000000;
int startval,endval;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &totalnodes); // get totalnodes
MPI_Comm_rank(MPI_COMM_WORLD, &mynode);
// get mynode
int lin=y-x;
‫حل التمرين‬
startval = (lin*(mynode))/totalnodes+x;
endval =(lin*(mynode+1))/totalnodes+x;
for(int i=startval;i<=endval;i++){
bool t=true;
for(int m=2;m<i;m++){
if(i%m==0){
t=false;
break;
}
}
if(t){
cout<<i<<"--";
}
}
system("pause");
MPI_Finalize();
}