ГПУ програмирање са Ц ++

Gpu Programming With C



У овом водичу ћемо истражити моћ програмирања ГПУ -а са Ц ++. Програмери могу очекивати невероватне перформансе са Ц ++, а приступ феноменалној снази ГПУ-а са језиком ниског нивоа може донети неке од најбржих рачунања која су тренутно доступна.

Захтеви

Иако свака машина која може да покреће модерну верзију Линука може да подржава Ц ++ компајлер, биће вам потребан ГПУ заснован на НВИДИА-и који ћете пратити заједно са овом вежбом. Ако немате ГПУ, можете покренути инстанцу са ГПУ-ом у Амазон Веб Сервицес или другом добављачу облака по вашем избору.







Ако одаберете физичку машину, проверите да ли су инсталирани управљачки програми за НВИДИА. Упутства за ово можете пронаћи овде: хттпс://линукхинт.цом/инсталл-нвидиа-дриверс-линук/



Поред управљачког програма, биће вам потребан и ЦУДА сет алата. У овом примеру користићемо Убунту 16.04 ЛТС, али доступна су преузимања за већину великих дистрибуција на следећој УРЛ адреси: хттпс://девелопер.нвидиа.цом/цуда-довнлоадс



За Убунту бисте изабрали преузимање засновано на .деб -у. Преузета датотека неће подразумевано имати .деб екстензију, па препоручујем да је преименујете у .деб на крају. Затим можете инсталирати помоћу:





судо дпкг име-пакета.деб

Вероватно ћете бити упитани да инсталирате ГПГ кључ, а ако је тако, следите упутства за то.

Када то учините, ажурирајте своја спремишта:



судо апт-гет упдате
судо апт-гет инсталлчуда

Када завршите, препоручујем поновно покретање како бисте били сигурни да је све правилно учитано.

Предности развоја ГПУ -а

ЦПУ -и обрађују много различитих улаза и излаза и садрже велики асортиман функција за не само бављење широким спектром програмских потреба, већ и за управљање различитим хардверским конфигурацијама. Они такође управљају меморијом, кеширањем, системском магистралом, сегментирањем и ИО функционалношћу, што их чини џеком свих заната.

ГПУ -и су супротни - садрже многе појединачне процесоре који су фокусирани на врло једноставне математичке функције. Због тога обрађују задатке много пута брже од ЦПУ -а. Специјализацијом за скаларне функције (функција која узима један или више улаза, али враћа само један излаз), постижу екстремне перформансе по цену екстремне специјализације.

Пример кода

У примеру кода, заједно додајемо векторе. Додао сам ЦПУ и ГПУ верзију кода за поређење брзине.
гпу-екампле.цпп садржај испод:

#инцлуде 'цуда_рунтиме.х'
#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде

типедефсати::цхроно::хигх_ресолутион_цлоцкЦлоцк;

#дефине ИТЕР 65535

// ЦПУ верзија функције векторског додавања
празнинавецтор_адд_цпу(инт *до,инт *б,инт *ц,интн) {
инти;

// Додајте векторске елементе а и б вектору ц
за (и= 0;и<н; ++и) {
ц[и] =до[и] +б[и];
}
}

// ГПУ верзија функције векторског додавања
__глобал__празнинавецтор_адд_гпу(инт *гпу_а,инт *гпу_б,инт *гпу_ц,интн) {
инти=тхреадИдк.Икс;
// Није потребна петља фор јер је време извођења ЦУДА
// ово ће провући ИТЕР пута
гпу_ц[и] =гпу_а[и] +гпу_б[и];
}

интглавни() {

инт *до,*б,*ц;
инт *гпу_а,*гпу_б,*гпу_ц;

до= (инт *)маллоц(ИТЕР* величина(инт));
б= (инт *)маллоц(ИТЕР* величина(инт));
ц= (инт *)маллоц(ИТЕР* величина(инт));

// Потребне су нам променљиве доступне ГПУ -у,
// па их цудаМаллоцМанагед пружа
цудаМаллоцМанагед(&гпу_а, ИТЕР* величина(инт));
цудаМаллоцМанагед(&гпу_б, ИТЕР* величина(инт));
цудаМаллоцМанагед(&гпу_ц, ИТЕР* величина(инт));

за (инти= 0;и<ИТЕР; ++и) {
до[и] =и;
б[и] =и;
ц[и] =и;
}

// Позовите функцију ЦПУ и одредите јој време
аутоцпу_старт=Цлоцк::Сада();
вецтор_адд_цпу(а, б, ц, ИТЕР);
аутоцпу_енд=Цлоцк::Сада();
сати::цена << 'вецтор_адд_цпу:'
<<сати::цхроно::дуратион_цаст<сати::цхроно::наносекунди>(цпу_енд-цпу_старт).цоунт()
<< 'наносекунде. н';

// Позовите ГПУ функцију и одредите јој време
// Троструке угаоне заграде су ЦУДА екстензија која омогућава
// параметри позива ЦУДА језгра који се прослеђују.
// У овом примеру преносимо један блок нити са ИТЕР нитима.
аутогпу_старт=Цлоцк::Сада();
вецтор_адд_гпу<<<1, ИТЕР>>> (гпу_а, гпу_б, гпу_ц, ИТЕР);
цудаДевицеСинцхронизе();
аутогпу_енд=Цлоцк::Сада();
сати::цена << 'вецтор_адд_гпу:'
<<сати::цхроно::дуратион_цаст<сати::цхроно::наносекунди>(гпу_енд-гпу_старт).цоунт()
<< 'наносекунде. н';

// Ослобађање меморије засноване на ГПУ функцији
цудаФрее(до);
цудаФрее(б);
цудаФрее(ц);

// Ослобађање меморије засноване на функцији ЦПУ-а
бесплатно(до);
бесплатно(б);
бесплатно(ц);

повратак 0;
}

Макефиле садржај испод:

ИНЦ= -И/уср/локалним/чуда/укључују
НВЦЦ=/уср/локалним/чуда/сам/нвцц
НВЦЦ_ОПТ= -стд = ц ++Једанаест

све:
$(НВЦЦ)$(НВЦЦ_ОПТ)гпу-екампле.цпп-илигпу-пример

чист:
-рм гпу-пример

Да бисте покренули пример, саставите га:

направити

Затим покрените програм:

./гпу-пример

Као што видите, верзија ЦПУ -а (вецтор_адд_цпу) ради знатно спорије од верзије ГПУ -а (вецтор_адд_гпу).

Ако није, можда ћете морати прилагодити ИТЕР дефиницију у гпу-екампле.цу на већи број. То је због тога што је време постављања ГПУ-а дуже од неких мањих петљи са интензивним процесором. Открио сам да 65535 добро ради на мојој машини, али ваша километража може да варира. Међутим, када обришете овај праг, ГПУ је драматично бржи од ЦПУ -а.

Закључак

Надам се да сте много научили из нашег увода у програмирање ГПУ -а са Ц ++. Горе наведени пример не постиже много, али демонстрирани концепти пружају оквир који можете користити за укључивање својих идеја како бисте ослободили моћ свог ГПУ -а.