Az első lépések a jcuda-val

A CUDA két különböző API-t kínál: a futásidejű API és a Driver API. Mindkettő nagyon hasonlít az alapvető feladatokra, például a memóriával való együttműködésre. Van azonban néhány fontos különbség köztük. Ezek közül a legfontosabb az a mód, ahogyan a rendszermagokat kezelik és végrehajtják.







Az eredeti CUDA futási időben a rendszermag-API-k meghatározása és összeállítása a C-fájlokkal történik. A forráskód NVCC-NVIDIA CUDA Compilátorral készült. Ez fordító használ egy másik fordító C (például GCC vagy VS C), hogy összeállítja a nettó C-kódot, majd vett összeállításához CUDA-összetevő - magok és a hívásokat (<<<.>>>). Az eredmény egy végrehajtható fájl, amely az egész programot ábrázolja.

Az NVCC természetesen nem használható Java programok összeállításához. A rendszermag felhívja a szintaxist<<<.>>>) Java-ban nincs használatban, és a fordítás után nincs egyetlen végrehajtható fájl sem. Ezért a JCuda Runtime API használatával nem lehet saját rendszermagot hívni. Ehelyett a JCuda Driver API-t kell használni, amint az alábbiakban látható.

A JCuda Runtime API elsősorban a CUDA Runtime könyvtárak, például a JCublas és a JCufft Java kötéseivel való interakcióra szolgál. A Java programozó, aki ezeket a könyvtárakat szeretné használni, és nem kíván saját rendszermagokat létrehozni, csak a JCuda Runtime API-val használható.

A JCuda használata előtt telepítenie kell a CUDA illesztőprogramot és az NVIDIA CUDA webhelyén letölthető eszközöket. Érdemes megjegyezni, hogy lehetnek késedelmek a CUDA és a JCuda új változatai között. A szoftver helyes telepítéséhez kövesse az oldalon található utasításokat.

Az SDK és a JCuda munka forráskódjaira nincs szükség, de az utóbbi hasznos lehet a CUDA működésének általános mechanizmusainak megértéséhez.

A helyes CUDA telepítés után töltse le a szükséges JCuda archívumot az operációs rendszertől függően. Az archívum tartalmaz JAR fájlokat és a megfelelő natív könyvtárakat.

A JAR fájlokat hozzá kell adni a CLASSPATH-hoz, és a natív könyvtáraknak elérhető Java helyszínen kell lenniük. A legtöbb esetben ez vagy az adott JVM java.library.path vagy a gyökérkönyvtár. Használhatja az operációs rendszer eszközeit is - például PATH vagy LD_LIBRARY_PATH.

Elsődleges tesztelés

Ez a rész elmagyarázza, hogyan kell futtatni a JCuda projektet a parancs konzollal. Azok számára, akik ismerik a JAR fájlok és a natív könyvtárak Java használatát, érdemes kihagyni ezt a szakaszt, és folytatni egy új projekt létrehozását a kedvenc IDE-jéből. Ellenkező esetben a következő lépéseket kell végrehajtania:

  • Másolja át a letöltött JCuda archívum összes fájlját egy mappába, és adja hozzá a "JCudaRuntimeTest.java" fájlt a következő tartalommal: import jcuda. ​​*; import jcuda.runtime. *; nyilvános osztályú JCudaRuntimeTest >
  • Fordítsd le a programot a következő parancs segítségével a projektben könyvtárban (az aktuális számot kell behelyettesíteni, hanem a „0.3.2a”): Windows: javac -CP „jcuda-0.3.2a.jar.” JCudaRuntimeTest.java Linux: javac -CP”. : jcuda-0.3.2a.jar JCudaRuntimeTest.class „” JCudaRuntimeTest.java Miután a fájl jön létre „ugyanabban a könyvtárban.
  • A program futtatása a következő paranccsal: Windows:;: ": Jcuda-0.3.2a.jar" java -CP "Jcuda-0.3.2a.jar" JCudaRuntimeTest Linux java -CP JCudaRuntimeTest Ekkor megjelenik a képernyőn megjelenő információkat a programban létrehozott indexről.






Magok létrehozása

Amint azt a bevezetőben már említettük, a Saját rendszermagok a Driver API segítségével indíthatók el. Ez a szakasz leírja a JCuda rendszeren belüli rendszermag létrehozásához szükséges szabványos munkafolyamatot. A legtöbb információ mind a CUDA, mind pedig a JCuda esetében érvényes. Tehát hasznosak lesznek a CUDA leírása, például a CUDA programozási útmutatója.

Kernel írása

A rendszermag kód pontosan úgy íródott, mint a CUDA esetében. Általában a rendszermag-kód egy külön fájlban található. A CUDA futásidejű API-ban a kernel gyakran egy nagyobb C fájl része. Ebben az esetben a JCuda figyelmen kívül hagy minden további kódot.

Figyelmet kell fordítani a következő pontra: amikor a rendszermagot a Driver API használatával hívják meg, a funkciót név szerint azonosítják. Ezért meg kell jegyezni, hogy extern "C", így a C fordító nem változtatja meg a nevét. Példa a vektor hozzáadására:

A rendszermag összeállítása

A rendszermag forráskódját NVCC-vel kell összeállítani. Ennek eredményeképpen létrejön egy olyan fájl, amelyet a Driver API segítségével lehet betölteni és végrehajtani. A rendszermag összeállításához két fájlformátum létezik:

  • A PTX egy ember által olvasható (de nehezen érthető) fájl, amely egyfajta "összeszerelő" kódot tartalmaz.
  • CUBIN (CUDA bináris) - egy adott GPU kódra fordítva, amelyet további költség nélkül hajtanak végre.

Korábban a CUBIN fájlokat mindenütt használták, de a PTX most előnyösebb, és hordozható, és használhatja a fordításokat.

A kernel betöltése és végrehajtása a JCuda-ban

A PTX és CUBIN fájlok JCuda Driver API-jának betöltése és végrehajtása ugyanaz, mint a CUDA Driver API-ban. Mindenekelőtt a modulot be kell tölteni, és a rendszermag függvényében egy mutatót kell fogadni: // A ptx fájl betöltése. CUmodule modul = új CUmodule (); cuModuleLoad (modul, "JCudaVectorAddKernel.ptx"); // A függvénymutatót a kernelfunkcióhoz kapja. CU funkció = új CUfunction (); cuModuleGetFunction (függvény, modul, "add");

Amikor a rendszermag hívásra kerül, megjelenik néhány Java nyelvi nyelvű Java nyelv. A kernelparaméterek beállításához szükséges funkciók meglehetősen összetettek a CUDA 3.2-ig és a CUDA 4.0-ig is. Ezeket a függvényeket felváltotta az, amelyik az összes rendszermag végrehajtási paramétereit átveszi. Ezenkívül az összes kernel bemeneti paramétert egyetlen üres ** pointerként fogadja el, amelyet Pointer osztály felhasználásával emulálnak. Így, paraméterek beállítása JCuda mag lehet még egyszerűbb, mint a CUDA: // Állítsa be a kernel paraméterek: pointer tömb // mutatók közül, amelyek a tényleges értékek. Pointer kernelParameters = Pointer.to (Pointer.to (új int []), Pointer.to (deviceInputA), Pointer.to (deviceInputB), Pointer.to (deviceOutput)); // Hívja a rendszermag funkciót. cuLaunchKernel (függvény, gridSizeX, 1, 1, // Rácsméret blockSizeX, 1, 1, // blokk dimenzióban 0, null, // Osztott memória mérete és a stream kernelParameters, null // kernel- és extra paraméterek);

Érdemes megjegyezni, hogy itt vannak olyan problémák, amelyek a C-re jellemzőek, nagyon óvatosaknak kell lenni a mutatókkal való együttműködés során.

Elvileg minden JCuda program jellegzetes mintázata van. Ez lehetővé teszi a JCuda további példákon alapuló tanulmányozását.




Kapcsolódó cikkek