Преглед
У овом водичу ћемо истражити снагу ГПУ програмирања са Ц-ом++. Програмери могу очекивати невероватне перформансе са Ц ++-ом, а приступ феноменалној снази ГПУ-а језиком ниског нивоа може дати неке од најбржих тренутно доступних рачунања.
Захтеви
Иако било која машина способна за покретање савремене верзије Линука може подржати Ц ++ компајлер, за праћење ове вежбе биће вам потребан ГПУ заснован на НВИДИА. Ако немате ГПУ, можете да завртите инстанцу засновану на ГПУ-у у Амазон Веб Сервицес-у или другом добављачу услуга у облаку по вашем избору.
Ако одаберете физичку машину, побрините се да имате инсталиране власничке управљачке програме НВИДИА. Упутства за ово можете пронаћи овде: хттпс: // линукхинт.цом / инсталл-нвидиа-дриверс-линук /
Поред управљачког програма, биће вам потребан ЦУДА алат. У овом примеру ћемо користити Убунту 16.04 ЛТС, али постоје доступна преузимања за већину главних дистрибуција на следећем УРЛ-у: хттпс: // програмер.нвидиа.цом / цуда-довнлоадс
За Убунту бисте изабрали .преузимање на основу деб-а. Преузета датотека неће имати .деб проширење по дефаулту, па препоручујем да га преименујете у а .деб на крају. Затим можете инсталирати са:
судо дпкг -и назив пакета.дебВероватно ће вам бити затражено да инсталирате ГПГ кључ, а ако јесте, следите упутства да бисте то урадили.
Када то учините, ажурирајте своја спремишта:
судо апт-гет упдатесудо апт-гет инсталл цуда -и
Када завршите, препоручујем поновно покретање како бисте били сигурни да је све правилно учитано.
Предности развоја ГПУ-а
ЦПУ обрађују много различитих улаза и излаза и садрже велики асортиман функција не само да се баве широким асортиманом програмских потреба већ и за управљање различитим хардверским конфигурацијама. Такође се баве меморијом, кеширањем, системском магистралом, сегментирањем и ИО функционалношћу, што их чини дизалицом свих трговина.
ГПУ-ови су супротно - садрже много појединачних процесора који су усредсређени на врло једноставне математичке функције. Због тога обрађују задатке много пута брже од ЦПУ-а. Специјализацијом за скаларне функције (функција која узима један или више улаза, али враћа само један излаз), постижу екстремне перформансе по цену екстремне специјализације.
Пример кода
У примеру кода додајемо векторе заједно. Додао сам ЦПУ и ГПУ верзију кода за поређење брзине.
гпу-пример.цпп садржај испод:
#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде
типедеф стд :: цхроно :: хигх_ресолутион_цлоцк Цлоцк;
#дефине ИТЕР 65535
// ЦПУ верзија функције векторског додавања
воид вецтор_адд_цпу (инт * а, инт * б, инт * ц, инт н)
инт и;
// Векторским елементима додајте елементе а и б
за (и = 0; и < n; ++i)
ц [и] = а [и] + б [и];
// ГПУ верзија функције векторског додавања
__глобал__ воид вецтор_адд_гпу (инт * гпу_а, инт * гпу_б, инт * гпу_ц, инт н)
инт и = тхреадИдк.Икс;
// Не треба за петљу јер је ЦУДА време извршавања
// ће пребацити ово ИТЕР пута
гпу_ц [и] = гпу_а [и] + гпу_б [и];
инт маин ()
инт * а, * б, * ц;
инт * гпу_а, * гпу_б, * гпу_ц;
а = (инт *) маллоц (ИТЕР * величина (инт));
б = (инт *) маллоц (ИТЕР * величина (инт));
ц = (инт *) маллоц (ИТЕР * величина (инт));
// Потребне су нам променљиве доступне ГПУ-у,
// па цудаМаллоцМанагед пружа ове
цудаМаллоцМанагед (& гпу_а, ИТЕР * сизеоф (инт));
цудаМаллоцМанагед (& гпу_б, ИТЕР * сизеоф (инт));
цудаМаллоцМанагед (& гпу_ц, ИТЕР * сизеоф (инт));
за (инт и = 0; и < ITER; ++i)
а [и] = и;
б [и] = и;
ц [и] = и;
// Позовите ЦПУ функцију и мерите време
ауто цпу_старт = Цлоцк :: нов ();
вецтор_адд_цпу (а, б, ц, ИТЕР);
ауто цпу_енд = Цлоцк :: нов ();
стд :: цоут << "vector_add_cpu: "
<< std::chrono::duration_cast
<< " nanoseconds.\n";
// Позовите ГПУ функцију и мерите време
// Троструки угаони носачи су ЦУДА рунтиме продужење које омогућава
// параметри позива ЦУДА кернела који се прослеђују.
// У овом примеру преносимо један блок нити ИТЕР нитима.
ауто гпу_старт = Цлоцк :: нов ();
вецтор_адд_гпу <<<1, ITER>>> (гпу_а, гпу_б, гпу_ц, ИТЕР);
цудаДевицеСинцхронизе ();
ауто гпу_енд = Цлоцк :: нов ();
стд :: цоут << "vector_add_gpu: "
<< std::chrono::duration_cast
<< " nanoseconds.\n";
// Ослободите расподјелу меморије засноване на ГПУ функцији
цудаФрее (а);
цудаФрее (б);
цудаФрее (ц);
// Ослободите расподјелу меморије засноване на ЦПУ функцији
бесплатно (а);
бесплатно (б);
бесплатно (ц);
ретурн 0;
Макефиле садржај испод:
ИНЦ = -И / уср / лоцал / цуда / инцлудеНВЦЦ = / уср / лоцал / цуда / бин / нвцц
НВЦЦ_ОПТ = -стд = ц ++ 11
све:
$ (НВЦЦ) $ (НВЦЦ_ОПТ) гпу-пример.цпп -о гпу-пример
чист:
-рм -ф гпу-пример
Да бисте покренули пример, компајлирајте га:
направитиЗатим покрените програм:
./ гпу-примерКао што видите, верзија процесора (вецтор_адд_цпу) ради знатно спорије од верзије ГПУ (вецтор_адд_гпу).
Ако није, можда ћете морати да прилагодите дефиницију ИТЕР у примеру гпу.цу на већи број. То је због тога што је време подешавања ГПУ-а дуже од неких мањих петљи које захтевају ЦПУ. Открио сам да 65535 добро ради на мојој машини, али ваша километража може варирати. Међутим, када очистите овај праг, ГПУ је драматично бржи од ЦПУ-а.
Закључак
Надам се да сте пуно научили из нашег увођења у ГПУ програмирање са Ц-ом++. Горњи пример не постиже много, али демонстрирани концепти пружају оквир који можете користити за укључивање својих идеја како бисте ослободили снагу свог ГПУ-а.