Forum » Programiranje » C++/CUDA - vprašanje
C++/CUDA - vprašanje
moose_man ::
Pri svojem delu v C++ veckrat pisem algoritme za obdelavo vec MB dolgih arrayev, ki jih optimiziram z SSE/AVX ukazi. Meritve z zanesljivimi orodji so pokazale, da tipična hitrost neparalelnega algoritma, ki jo s tem dosežem, znaša 2 ns / element arraya.
Na enem projektu bi moral v rednih casovnih intervalih taksen algoritem izvesti na (vsakic novih) 10 arrayih velikosti 5MB, torej za vse skupaj porabim priblizno 100ms casa. Profilerji kažejo, da se slaba polovica časa uporabi za store operacije, preostanek vzame pa sam algoritem oz. preostali ukazi.
Prekrasno bi bilo, če bi ta čas uspel zmanjšati za cca trikrat.
Ali se iz povedanega da ocenit, če se je vredno usmeriti v iskanje rešitev s programiranjem na grafični, ali pa se morda že v štartu vidi, da se to v tem primeru ne splača?
Na enem projektu bi moral v rednih casovnih intervalih taksen algoritem izvesti na (vsakic novih) 10 arrayih velikosti 5MB, torej za vse skupaj porabim priblizno 100ms casa. Profilerji kažejo, da se slaba polovica časa uporabi za store operacije, preostanek vzame pa sam algoritem oz. preostali ukazi.
Prekrasno bi bilo, če bi ta čas uspel zmanjšati za cca trikrat.
Ali se iz povedanega da ocenit, če se je vredno usmeriti v iskanje rešitev s programiranjem na grafični, ali pa se morda že v štartu vidi, da se to v tem primeru ne splača?
- spremenilo: moose_man ()
pegasus ::
Lahko napišeš vsaj psevdokodo, kaj z elementi v arrayu počneš?
Če so te operacije neodvisne med elementi, lahko načeloma izvedeš vse naenkrat. V tem primeru ti bo gpu to omogočil, računaj da boš moral nanj prenesti podatke in iz njega prenesti rezultate. Kar je lahko spet ozko grlo.
Če so operacije odvisne med seboj in si jih s trenutnim algoritmom prisiljen izvajati sekvečno, razmisli o menjavi algoritma za takega, ki ti to odvisnost zaobide in ti omogoči paralelizem, četudi je manj učinkovit na papirju.
Če znaš izmeriti čas izvajanja v ns, potem boš znal izmeriti tudi čas kopiranja iz rama v L3 oz. L2 in nazaj. Razmisli, če ti je to ozko grlo ali ne in ali se ti splača nafehtati za hw z večjim memory bandwidthom.
Če so te operacije neodvisne med elementi, lahko načeloma izvedeš vse naenkrat. V tem primeru ti bo gpu to omogočil, računaj da boš moral nanj prenesti podatke in iz njega prenesti rezultate. Kar je lahko spet ozko grlo.
Če so operacije odvisne med seboj in si jih s trenutnim algoritmom prisiljen izvajati sekvečno, razmisli o menjavi algoritma za takega, ki ti to odvisnost zaobide in ti omogoči paralelizem, četudi je manj učinkovit na papirju.
Če znaš izmeriti čas izvajanja v ns, potem boš znal izmeriti tudi čas kopiranja iz rama v L3 oz. L2 in nazaj. Razmisli, če ti je to ozko grlo ali ne in ali se ti splača nafehtati za hw z večjim memory bandwidthom.
moose_man ::
Algoritem izvaja interpolacijo s pomocjo koordinat; v vec knjiznicah temu recejo remapping (ne vem pa kaksen je splosen izraz). Psevdokoda:
Operacije torej SO neodvisne druga od druge (in to seveda ze izkoriscam v implementaciji z AVX). Morda v prvem postu nisem bil jasen - z neparalelnostjo algoritmov sem imel v mislih to, da tecejo le v enem threadu. Operacije pa se z AVX ukazi seveda izvajajo na SIMD (single instruction multiple data) nacin.
A je mozno vnaprej "cez palec" (red velikosti) oceniti kaksen delay prinese prenasanje podatkov na GPU in nazaj?
Hvala tudi za zadnji nasvet. Aja, pa se to: do estimatea 2 ns / element sem prisel tako, da sem med delovanjem programa racunal povprecen cas trajanja celotnega algoritma, nato pa povprecen cas delili s stevilom elementov. Nisem benchmarkal vsake operacije posebej. Sem pa meritve ponovil z arrayi razlicnih velikosti in prisel vedno do enake ocene.
void interpolation(vector const& source, vector const& coordinates, vector& output) { for(i = 0; i < N; ++i) { c = coordinates[i]; low = floor(c); high = ceil(c); output[i] = (high - c)*source[low] + (c - low)*source[high]; } }
Operacije torej SO neodvisne druga od druge (in to seveda ze izkoriscam v implementaciji z AVX). Morda v prvem postu nisem bil jasen - z neparalelnostjo algoritmov sem imel v mislih to, da tecejo le v enem threadu. Operacije pa se z AVX ukazi seveda izvajajo na SIMD (single instruction multiple data) nacin.
A je mozno vnaprej "cez palec" (red velikosti) oceniti kaksen delay prinese prenasanje podatkov na GPU in nazaj?
Hvala tudi za zadnji nasvet. Aja, pa se to: do estimatea 2 ns / element sem prisel tako, da sem med delovanjem programa racunal povprecen cas trajanja celotnega algoritma, nato pa povprecen cas delili s stevilom elementov. Nisem benchmarkal vsake operacije posebej. Sem pa meritve ponovil z arrayi razlicnih velikosti in prisel vedno do enake ocene.
Zgodovina sprememb…
- spremenil: Senitel ()
pegasus ::
Ok, kot prvi korak si poglej openMP in uredi zgornji zanko tako, da bo tekla vzporedno na več threadih. To bi ti moralo prinesti skoraj linearno pospešitev glede na število threadov z minimalnim vložkom v programiranje.
Naslednji korak ti je lahko openACC - z njim na podobno enostaven način preneseš izvajanje teh zank na gpu, s tem da ti je ves mehanizem zadaj (kopiranje etc) povečini skrit in se ti ni potrebno ukvarjati z njim.
Šele če ti to ne prinese dovolj pohitritve, pa le pogumno cudo v roke. Ali mogoče še raje OpenCL ;)
Kopiranje na gpu in nazaj je omejeno s hitrostjo PCI vodila, ki je danes (PCIe v3) 1GB/s per lane, torej gpu na x16 vodilu nekje max 16GB/s, v praksi nekaj manj.
Naslednji korak ti je lahko openACC - z njim na podobno enostaven način preneseš izvajanje teh zank na gpu, s tem da ti je ves mehanizem zadaj (kopiranje etc) povečini skrit in se ti ni potrebno ukvarjati z njim.
Šele če ti to ne prinese dovolj pohitritve, pa le pogumno cudo v roke. Ali mogoče še raje OpenCL ;)
Kopiranje na gpu in nazaj je omejeno s hitrostjo PCI vodila, ki je danes (PCIe v3) 1GB/s per lane, torej gpu na x16 vodilu nekje max 16GB/s, v praksi nekaj manj.
moose_man ::
Hvala za te nasvete, prisli bodo zelo prav.
PS: izvajanje algoritma v vec threadih sem v startu crtal, ker to ne bi resilo vseh tezav. Prevelik latency algoritma (ki je sicer primaren obstacle) ni edini problem; tezave so tudi zaradi tega ker bi uvedba tega algoritma porabila znaten prevelik delez procesorske moci glede na to, ki nam je trenutno na voljo.
PS: izvajanje algoritma v vec threadih sem v startu crtal, ker to ne bi resilo vseh tezav. Prevelik latency algoritma (ki je sicer primaren obstacle) ni edini problem; tezave so tudi zaradi tega ker bi uvedba tega algoritma porabila znaten prevelik delez procesorske moci glede na to, ki nam je trenutno na voljo.
pegasus ::
Torej si omejen s hardverom in imaš hkrati zahtevo po rezultatih v predpisanem času? Good luck, to se sliši kot en low level asm projekt za pol leta, po možnosti v kakem realtime OSu ;) Če imaš čas in voljo, vsekakor zanimiv izziv.
Lahko poveš kaj več, kaj konkretno tu delate?
Eno področje optimizacije, ki si ga lahko še pogledaš, je cache. Poskrbeti moraš, da so vse io operacije cache aligned, kar je odvisno od tega, kakšno cache topologijo uporablja konkreten proc, na katerem laufaš zadeve. Če še nisi, preštudiraj ta priročnik. V prvem postu omenjaš, da ti trenutno gre polovica časa v pisanje - verjetno lahko ta čas precej zmanjšaš.
Lahko poveš kaj več, kaj konkretno tu delate?
Eno področje optimizacije, ki si ga lahko še pogledaš, je cache. Poskrbeti moraš, da so vse io operacije cache aligned, kar je odvisno od tega, kakšno cache topologijo uporablja konkreten proc, na katerem laufaš zadeve. Če še nisi, preštudiraj ta priročnik. V prvem postu omenjaš, da ti trenutno gre polovica časa v pisanje - verjetno lahko ta čas precej zmanjšaš.
moose_man ::
@pegasus: implementacija ze uporablja alignane loade in store in prirocnik poznam. Hvala pa vseeno.
Senitel ::
Glede na zgornjo psevdo kodo lahko spakiraš podatke v teksturo, jo uploadaš na GPU in uporabiš texture filtering hardware, ki ga imajo GPU-ji... Cela tistale tvoja koda se spremeni efektivno v eno vrstico:
Zadeva bo tolk hitra kot boš imel na razpolago bandwidtha na GPU-ju. Trivialen case v bisvu (še ALU-jev praktično ne rabiš).
__global__ void interpolation(cudaTextureObject_t source, float *coordinates, float *output) { const int i = blockIdx.x * blockDim.x + threadIdx.x; output[i] = tex1Dfetch<float>(source, coordinates[i]); // 1D koordinate }
Zadeva bo tolk hitra kot boš imel na razpolago bandwidtha na GPU-ju. Trivialen case v bisvu (še ALU-jev praktično ne rabiš).
srus ::
Profilerji kažejo, da se slaba polovica časa uporabi za store operacije, preostanek vzame pa sam algoritem oz. preostali ukazi.
Če je razmerje med časom potrebnim za obdelavo podatkov in časom potrebnim za shranjevanje podatkov 1 : 1, potem bi na hitro sklepal da:
- že imaš zelo hiter algoritem
- imaš zelo počasen pomnilnik
Ali morda uporabljaš SMP z dvema procesorjema in NUMA pomnilnikom? Kjer so dostopi do pomnilnika interleaved med bankami?
Kateri OS uporabljaš? Če ne želiš uporabljati multi threaded variante, ki bi tekla na večih corih, se na Linuxu, da enostavno znebiti interruptov in schedulinga na coru, ki ga polno posvetiš svojemu algoritmu.
Glede na 1:1 razmerje bi preveril tudi kaj se da narediti na DMA prenosih iz zunanje enote v cache procesorja in obratno.
Vredno ogleda ...
Tema | Ogledi | Zadnje sporočilo | |
---|---|---|---|
Tema | Ogledi | Zadnje sporočilo | |
» | [Android][Java] Povečanje hitrosti algoritmaOddelek: Programiranje | 1172 (753) | Legoless |
» | Matrix multiplication program Pycuda in MathlabOddelek: Programiranje | 2540 (2115) | Senitel |
» | Digitalna evolucija (strani: 1 2 3 4 … 26 27 28 29 )Oddelek: Znanost in tehnologija | 75567 (25736) | pietro |
» | It means business (strani: 1 2 3 4 5 6 7 8 )Oddelek: Znanost in tehnologija | 28286 (14285) | Thomas |
» | Desktop aplikacije večinoma niso multithreaded??? (strani: 1 2 )Oddelek: Programiranje | 4881 (4127) | Gundolf |