نیلوفر آرازخانی
نیلوفر آرازخانی
خواندن ۲ دقیقه·۴ سال پیش

اولین قدم در محاسبات موازی

این بار محاسبات موازی را با جزییات بیشتری باهم نگاه میکنیم. محاسبات موازی برای سریع تر انجام شدن برنامه ها استفاده میشه.

حال فرض کنید میخواهیم یک برنامه را به صورت موازی اجرا کنیم. برای اجرای موازی برنامه نیاز هست که کامپیوتر ما دارای GPU باشد. GPU که مخفف Graphics Processing Units هست. GPU کار کرد سریع تری نسبت به CPU دارد ولی برای استفاده از آن نیاز است که CPU همراهی اش کند! یعنی GPUبه تنهایی کار را سریع نمیکند و در ارتباط با CPU است که میتواند کارها را سریع کند. همین طور که در تصویر زیر پیداست GPU بخش هایی از کد را اجرا میکند که اجرای آن سنگین تر است که به این قسمت از کد Kernels گفته میشه. CPU و GPU هر کدام Memory خودشان را دارند و با استفاده از Bus با یکدیگر در ارتباط هستند و Data ردو بدل میکنند.

ارتباط بین CPU و GPU
ارتباط بین CPU و GPU

خب حالا فرض کنید میخواهیم برنامه ای بنویسیم که به صورت موازی کار کند. در واقع باید این برنامه بتواند برای اجرا شدن از GPU استفاده کند و کدها بر روی ساختار موازی آن اجرا شوند. برای این کار نیاز است که از زبان برنامه نویسی Cuda استفاده شود. این زبان یک زبان برگرفته شده از c/c++ است که به NVIDIA GPU اجازه مدیریت حافظه و تعریف کرنل برای برنامه را میدهد. هر GPUشامل تعدادی Multiprocessor است که هر کدام از این Multiprocessor ها چند coreدارند و به همین دلیل میتوان بر روی این core ها برنامه را به صورت موازی اجرا کرد. تصویر پایین صورت دقیق تری از تصویر بالاست.

هر GPUدارای تعدادی multicore است که هر کدام از آنها تعدادی core دارند
هر GPUدارای تعدادی multicore است که هر کدام از آنها تعدادی core دارند



برنامه نویسی در Cuda

تا اینجا دیدیم ساختار GPU به چه صورته، حالا برای اینکه بتونیم در برنامه نویسی از این multiprocessor ها و core ها استفاده کنیم، نیاز هستش که بتونیم به صورت Abstract این موضوعات سخت افزاری را بر روی برنامه بیاریم. برای همین از Block به عنوان نمادی برای Multiprocessorها استفاده شده و از thread برای بیان coreها استفاده شده.

برای دیدن دو تا کد یکی در C++ و یکی در Cuda خودتون رو آماده کنید!

در برنامه نویسی C++ میخواهیم یک آرایه را با مقادیری پر کنیم:

for( i=0; i<N; i++){ result[i]=2*i; }

اگر بخواهیم به این صورت عمل کنیم، هر بار یک قسمت از دیتا تغیر میکند یعنی اجرای برنامه را اگر به صورت تصویر نمایش دهیم مانند شکل زیر است:

قسمت های آبی را آرایه در نظر بگیرید و فلش قرمز رنگ را جریان اجرا
قسمت های آبی را آرایه در نظر بگیرید و فلش قرمز رنگ را جریان اجرا

حال همین برنامه را باید به صورت موازی و با استفاده از multiprocessorدر Cuda اجرا کنیم! شاید همین الان حدس زده باشید که باید برنامه به صورت موازی و برای هر کدام از محاسبات یک thread در نظر بگیریم! و تصویر آن به صورت زیر است:

 اجرای موازی بر روی Cuda
اجرای موازی بر روی Cuda

برای اجرای این برنامه بر روی cuda یک function باید تعریف کرد. قبل از اون بهتره با یک تایپ جدید در Cuda آشنا شد! به نام dim3.

dim3 MyVariable=(12, 13,14) //MyVariable.x = 12 , MyVairable.y=13, MyVariable.z=14

حالا که این تایپ جدید رو دیدیم بریم برای نوشتن این حلقه در Cuda.

__global__ void MyFunction(int *result) { int i=threadId.x; result[i]=2*i; } dim3 blocksPerGrid(1,1,1); //declaring number of blocks (SM in second Image) dim3 threadsPerBlock(N,1,1); //declare number of threads(Core in second Image) MyFunction<<<blocksPerGrid,threadsPerBlock>>>(result); //call the function in this way! using //<<<>>>

شاید اولش که این تکه کد رو میبینید این جوری بشید O_o ولی در واقع زیاد چیز عجیبی نیست! به عنوان آخرین مطلب این پست این تکه کد رو توضیح میدم:

خط اول __global__ داره میگه این کد باید روی GPU اجرا بشه! threadIdهم برای هر thread خود برنامه به صورت unique در نظر گرفته و از تایپ dim3 هستش. تعداد بلاک ها و تعداد thread ها هم خودمون تعریف میکنیم و در آخر با توجه به تعداد بلاک و threadهای تعریف شده برنامه اجرا میشه :)

اگه تا اینجا خوندید، مرسی :)


محاسباتکامپیوترموازیبرنامه نویسی
شاید از این پست‌ها خوشتان بیاید