Tag Archives: OpenCL

OpenCL, nVidia a rozuzlenie

Tak nakoniec to vyzerá, že celá tá šaškáreň s OpenCL (viď môj predchádzajúci článok) sa oplatila. Zabil som s tým síce neskutočné množstvo času, ale nakoniec som v hodnotení skončil prvý v skupine 🙂

Za náročnosť úlohy vraví aj fakt, že z 35 študentov, čo na tento predmet chodia, odovzdalo úlohu len 13. A z týchto trinástich riešení správne fungovalo len sedem. Teda rovných 20%. Nič moc, keď si vezmete, že to bola úplne obyčajná úloha pre študentov magisterského štúdia informatiky.

Moje riešenie dopadlo v teste najlepšie – s priemerným zrýchlením (na troch rôzne veľkých vstupoch) 44,536x. Vzorové riešenie, ktoré vypracoval zadávateľ úlohy, dosiahlo priemerné zrýchlenie 43,852, to moje riešenie teda bolo ešte o čosi lepšie, ale povedal by som, že to bolo spôsobené len nedostatkom času zo strany cvičiaceho.

V každom prípade, týmto pádom mám už teraz istú známku z tohto predmetu, nemusím sa teda ďalej znervózňovať, čo je pozitívne. Kicking back and enjoying the feeling… 🙂

Reklamy

nVidia, OpenCL a frustrácia

Toto bude jeden z tých technickejších článkov, takže ak nepatríte k tým, ktorých tieto veci zaujímajú, môžete to tu pokojne preskočiť – alebo čítať ďalej pre náhľad do sveta, ktorý tak často nevidíte 🙂

Stručný úvod: na jednom predmete v škole (programovanie v paralelnom prostredí) sme dostali za úlohu napísať jednoduchý algoritmus pre výpočet fyzikálneho modelu pohybu častí. V podstate sa jednalo o veľmi primitívny model “gravitačného” rozmiestnenia vrcholov grafu. Mali sme použiť technológiu OpenCL 1.1 pre akcelerovanie výpočtov na grafickom HW.

So far, so good. Po iniciálnom zoznámení s technológiou som strávil netriviálne množstvo času (= cca 14 hodín) implementáciou prvotného návrhu riešenia. Čo sa nakoniec aj podarilo – môj kód bežal (nie práve super efektívne, ale predsa) a testy prechádzali pre prvý zo vzorových vstupov.

Nasledujúci deň som ešte vyoptimalizoval jeden z kernelov pre spracovanie hrán grafu a tešil som sa, že mám hotovo. Aké veľké bolo moje prekvapenie, keď sam zistil, že aj keď moje riešenie funguje správne na prvom vzorovom vstupe, na druhom a treťom má problém.

Prekvapujúce to bolo hlavne z toho dôvodu, že sme k úlohe dostali aj vzorové sériové CPU-bound riešenie, voči ktorému sa potom naše OpenCL riešenie bude porovnávať. A môj kód pre OpenCL kernely vychádzal z veľkej časti práve z tohto vzorového kódu. A napriek tomu dával iné výsledky. Nie o veľa, ale dosť na to, aby prekročil toleranciu 1% nastavenú vo validátore výsledkov.

Po troche diskusie s cvičiacim a experimentovania sa mi podarilo upraviť moje kernely tak, aby validácia prešla aj na vstupe číslo dva. Vysvitlo, že pow(x, 2) a pown(x, 2) != x * x, ak je x typu float. Použitie pow bolo samozrejme zbytočné – chybne som usudzoval, že intrinsická funkcia pow bude efektívnejčia ako násobenie. Well, nie je. A to bol jeden zo zdrojov nepresnosti v mojich kerneloch. Po nahradení obyčajným násobením moje riešenie prešlo validáciou aj na druhom vstupe.

Na treťom vstupe sa tiež zlepšilo – namiesto zlyhania v prvej iterácii výpočtu zlyhalo až v tretej. Sill not good enough, keďže pri validácii musí prejsť aspoň 50 iterácií bez chyby. Po ďalšom ladení som usúdil, že môj kód už nie je možné viac priblížiť k dodanému vzoru pre CPU. Vzal som teda kód kernelu a namiesto na GPU som ho vykonal na CPU (PRESNE rovnaký kód). Výsledok? Rozdielne hodnoty za ôsmym desatinným miestom.

Vysvitlo, že intrinsická funkcia sqrt v OpenCL počíta trochu inak ako std::sqrt. V OpenCL 1.1 implementácii od nVidie totiž nie je v súlade s IEEE 754, zatiaľ čo std::sqrt je. A toto je problém, pretože, na rozdiel od prípadu s pow, sqrt nie je možné jednoducho nahradiť. A navyše je vo výpočte táto funkcia nutná.

Človek by si povedal, že taký malý rozdiel (8 signifikantných desatinných miest) je zanedbateľný. To je ale pravda len pre prípady, keď sa táto nepresnosť nezačne kumulovať. Čo, nanešťastie, v tomto prípade nastane. Počítam v podstate intertakcie častíc “každá s každou”, takže keď máme desiatky tisíc bodov, nepresnosti sa začnú sčítavať a nakoniec prekročia povolené hranice. Preto moje riešenie fungovalo pre vstupy 1 a 2 – majú len 1k a 4k bodov. Vstup 3 ich má 16k.

Uvidíme, čo z toho vylezie. Som v kontakte so zadávateľom úlohy, možno bude mať nejaký usefull insight. Ak nie cez mail, asi si dohodnem konzultáciu, aby som mu mohol môj kód predviesť a zverifikovať, že nie je chybný v nejakom obskurnom aspekte.

Nech je to ako chce (a ak ste vydržali čítať až sem 🙂 ), veľmi som na kombináciu OpenCL 1.1 a nVidia HW nadával (nemám k dispozícii HW od AMD, takže neviem povedať, či je situácia lepšia tam). Naše riešenia sa budú po odovzdaní vyhodnocovať na kartách Tesla K20, takže opať nVidia. Taká hlúposť, ale stojí to človeka nekonečné množstvo času. Víkend zabitý, damn it.

Ale aspoň som sa naučil niečo, čo som vždy chcel, ale nenašiel dosť času a odhodlania ísť do toho – programovanie high-performance kódu pre GPU 🙂

UPDATE 8.4.2014

Tak sa nakoniec ukázalo, že som vo svojom zápase s presnosťou nebol sám. Minulý vikend nám všetkým prišiel e-mail od zadávateľa, že sa mu ozvalo hneď niekoľko ďalších ľudí, ktorí mali problémy. Nakoniec bol nútený upraviť systém vyhodnocovania presnosti riešenia a zvýšiť toleranciu.

Mal som teda v konečnom dôsledku pravdu – vyhodnocovanie bolo dosť prísne. V každom prípade, moje riešenie je odladené, funguje out-of-the-box aj s novým vyhodnocovačom a mám teda po starostiach. Screw it! 🙂