Noțiuni de bază cu jcuda

CUDA oferă două API-uri diferite: API-ul Runtime și API-ul Driver. Ele sunt ambele foarte asemănătoare în ceea ce privește sarcinile de bază, cum ar fi lucrul cu memoria. Cu toate acestea, există unele diferențe importante între ele. Cea mai importantă dintre acestea este modul în care sunt gestionate kernelurile și modul în care acestea sunt executate.







În programul CUDA Runtime original, API-urile kernel-ului sunt definite și compilate cu fișierele C. Codul sursă este compilat cu NVCC - compilatorul NVIDIA CUDA. Acest compilator utilizează un alt compilator C (de exemplu, GCC sau VS C) pentru a compila codul pur C, apoi ia compilația componentei CUDA - nucleele și apelurile lor (<<<.>>>). Rezultatul este un fișier executabil reprezentând întregul program.

Desigur, NVCC nu poate fi folosit pentru a compila programe Java. Sintaxa apelului kernelului<<<.>>>) nu este folosită în Java, iar după compilare nu există un singur fișier executabil creat. Prin urmare, nu există nicio modalitate de a apela propriile kernel-uri utilizând API-ul JCuda Runtime. În schimb, ar trebui să se utilizeze API-ul Driver JCuda, așa cum se va arăta mai jos.

API-ul JCuda Runtime este destinat în principal interacțiunii cu legăturile Java ale bibliotecilor CUDA Runtime, cum ar fi JCublas și JCufft. Un programator Java care dorește să folosească aceste biblioteci și nu dorește să-și creeze propriile kernel-uri poate face doar cu API-ul JCuda Runtime.

Înainte de a putea utiliza JCuda, trebuie să instalați driverul CUDA și instrumentele care pot fi descărcate pe site-ul Web NVIDIA CUDA. Merită menționat faptul că pot exista întârzieri între lansările de noi versiuni ale CUDA și JCuda. Pentru instalarea corectă a acestui software, trebuie să urmați instrucțiunile de pe site.

SDK și exemple de cod sursă pentru munca JCuda nu sunt necesare, însă acestea din urmă pot fi utile pentru a înțelege mecanismele generale ale funcționării CUDA.

După instalarea corectă CUDA, ar trebui să descărcați arhiva JCuda necesară, în funcție de sistemul de operare. Arhiva conține fișiere JAR și bibliotecile native corespunzătoare.

Fișierele JAR trebuie adăugate la CLASSPATH, iar bibliotecile native trebuie să fie amplasate într-o locație Java accesibilă. În majoritatea cazurilor, aceasta este fie java.library.path a JVM-ului particular, fie directorul rădăcină al proiectului. De asemenea, puteți utiliza instrumentele sistemului de operare - de exemplu, PATH sau LD_LIBRARY_PATH.

Testarea primară

Această secțiune explică modul de rulare a proiectului JCuda folosind consola de comandă. Pentru cei care sunt familiarizați cu utilizarea fișierelor JAR și a bibliotecilor native din Java, poate fi util să treceți peste această secțiune și să continuați să creați un nou proiect din IDE preferat. În caz contrar, trebuie să efectuați următorii pași:

  • Copiați toate fișierele din arhiva JCuda descărcate într-un singur dosar și adăugați acolo fișierul "JCudaRuntimeTest.java" cu următorul conținut: import jcuda. ​​*; import jcuda.runtime. *; clasa publică JCudaRuntimeTest >
  • Compile programul utilizând următoarea comandă în directorul de proiect (numărul real ar trebui să fie substituit în loc de „0.3.2a“): În Windows: -cp javac „; jcuda-0.3.2a.jar.“ JCudaRuntimeTest.java Pe Linux: javac -cp“. : jcuda-0.3.2a.jar JCudaRuntimeTest.class „“ JCudaRuntimeTest.java După ce acest fișier este creat „în același director.
  • Rulați acest program cu următoarea comandă: În Windows:;: java -cp JCudaRuntimeTest Pe Linux java -cp JCudaRuntimeTest vor fi afișate pe informațiile de ecran: "Jcuda-0.3.2a.jar." "Jcuda-0.3.2a.jar." despre indexul creat în program.






Crearea de nuclee

Așa cum sa spus în introducere, kernelurile proprii pot fi lansate utilizând driverul API. Această secțiune descrie fluxul de lucru standard pentru crearea unui kernel în cadrul JCuda. Cele mai multe informații se aplică atât pentru CUDA, cât și pentru JCuda. Astfel, resursele care descriu CUDA, de exemplu, Ghidul de programare CUDA, vor fi utile.

Scrierea unui kernel

Codul kernel-ului este scris exact așa cum se face pentru CUDA. De obicei, codul kernelului este localizat într-un fișier separat. În aplicația CUDA Runtime API, kernelul face parte adesea dintr-un fișier C mai mare. În acest caz, orice cod suplimentar va fi ignorat de JCuda.

Trebuie acordată atenție următorului punct: atunci când kernel-ul este invocat utilizând Driver API, funcția va fi identificată după nume. Prin urmare, ar trebui să fie remarcat ca extern "C", astfel încât compilatorul C nu își schimbă numele. Exemplu de funcție de adăugare vectorială:

Compilarea kernelului

Codul sursă al kernel-ului trebuie să fie compilat cu NVCC. Ca rezultat, va fi creat un fișier care poate fi încărcat și executat utilizând driverul API. Există două formate de fișiere pentru compilarea kernel-ului:

  • PTX este un fișier care poate fi citit de om (dar destul de greu de înțeles) care conține un fel de cod de "asamblare".
  • CUBIN (CUDA binar) - compilat pentru un anumit cod GPU, care va fi executat fără costuri suplimentare.

Anterior, fișierele CUBIN au fost utilizate peste tot, dar PTX este mai preferabil acum, care sunt portabile și utilizează compilația în zbor.

Încărcarea și execuția kernel-ului în JCuda

Procesul de încărcare și executare a kernel-ului în API-ul Driver JCuda din fișierele PTX și CUBIN este același, la fel ca în API-ul Driver CUDA. Mai întâi, modulul trebuie să fie încărcat și un pointer la funcția de kernel este primit: // Încărcați fișierul ptx. Modul CUmodule = nou modul CU (); cuModuleLoad (modul, "JCudaVectorAddKernel.ptx"); // Obțineți un pointer de funcții pentru funcția de kernel. Funcția CUfun = CUfuncție nouă (); cuModuleGetFunction (funcție, modul, "adăugați");

Când se solicită kernelul, sunt afișate unele limbi limitate în limbajul Java. Caracteristică Setarea parametrilor kernel-ului sunt destul de complexe în versiuni CUDA 3.2, precum și CUDA 4.0. Aceste funcții au fost înlocuite de una care ia toate parametrii de execuție a kernel-ului. În plus, acesta primește toți parametrii de intrare ai nucleului ca un vid ** pointer, emulat prin intermediul pointer catre clasa. Astfel, setarea parametrilor JCuda de miez poate fi chiar mai ușor decât în ​​CUDA: // Configurarea parametrilor de kernel: un pointer la un tablou // de indicii care punct la valorile reale. Pointer kernelParameters = Pointer.to (Pointer.to (nou int []), Pointer.to (deviceInputA), Pointer.to (deviceInputB), Pointer.to (deviceOutput)); / / Apelați funcția kernel-ului. cuLaunchKernel (funcția, gridSizeX, 1, 1, // dimensiune Grid blockSizeX, 1, 1, // Block dimensiune 0, null, // Dimensiune memorie partajată și flux kernelParameters, null // sâmbure și parametri suplimentari);

Merită menționat faptul că aici există probleme tipice pentru C - trebuie să fii extrem de atent atunci când lucrezi cu pointeri.

În principiu, toate programele JCuda au un model caracteristic. Acest lucru permite studierea ulterioară a JCuda pe baza exemplelor.







Articole similare

Trimiteți-le prietenilor: