2015-09-12 1 views
4

J'ai dit en this question que j'avais un problème de chargement des modules ptx dans JCuda et après l'idée de @ talonmies, j'ai implémenté une version JCuda de sa solution pour charger plusieurs fichiers ptx et les charger comme module unique. Voici la partie correspondante du code:JIT dans JCuda, chargement de plusieurs modules ptx

import static jcuda.driver.JCudaDriver.cuLinkAddFile; 
import static jcuda.driver.JCudaDriver.cuLinkComplete; 
import static jcuda.driver.JCudaDriver.cuLinkCreate; 
import static jcuda.driver.JCudaDriver.cuLinkDestroy; 
import static jcuda.driver.JCudaDriver.cuModuleGetFunction; 
import static jcuda.driver.JCudaDriver.cuModuleLoadData; 

import jcuda.driver.CUjitInputType; 
import jcuda.driver.JITOptions; 
import jcuda.driver.CUlinkState; 
import jcuda.driver.CUfunction; 

public class JCudaTestJIT{ 

    private CUmodule module; 
    private CUfunction functionKernel; 

    public void prepareModule(){ 
     String ptxFileName4 = "file4.ptx"; 
     String ptxFileName3 = "file3.ptx"; 
     String ptxFileName2 = "file2.ptx"; 
     String ptxFileName1 = "file1.ptx"; 

     CUlinkState linkState = new CUlinkState(); 
     JITOptions jitOptions = new JITOptions(); 
     cuLinkCreate(jitOptions, linkState); 

     cuLinkAddFile(linkState, CUjitInputType.CU_JIT_INPUT_PTX, ptxFileName4, jitOptions); 
     cuLinkAddFile(linkState, CUjitInputType.CU_JIT_INPUT_PTX, ptxFileName3, jitOptions); 
     cuLinkAddFile(linkState, CUjitInputType.CU_JIT_INPUT_PTX, ptxFileName2, jitOptions); 
     cuLinkAddFile(linkState, CUjitInputType.CU_JIT_INPUT_PTX, ptxFileName1, jitOptions); 

     long sizeOut = 32768; 
     byte[] image = new byte[32768]; 

     Pointer cubinOut = Pointer.to(image); 

     cuLinkComplete(linkState, cubinOut, (new long[]{sizeOut})); 

     module = new CUmodule(); 

     // Load the module from the image buffer 
     cuModuleLoadData(module, cubinOut.getByteBuffer(0, 32768).array()); 

     cuLinkDestroy(linkState); 

     functionKernel = new CUfunction(); 
     cuModuleGetFunction(functionKernel, module, "kernel"); 
    } 

    // Other methods 
} 

Mais j'ai eu l'erreur de CUDA_ERROR_INVALID_IMAGE à appeler la méthode cuModuleLoadData. Pendant le débogage, j'ai vu qu'après avoir appelé la méthode cuLinkComplete et que j'ai passé le tableau image comme sortie, le tableau est toujours inchangé et clair. Est-ce que je passe le paramètre de sortie correctement? Est-ce ainsi que l'on peut passer une variable par référence dans JCuda?

+0

Vos fichiers d'entrée ont des extensions '.cu'. Si elles sont source CUDA C, elles ne peuvent pas être compilées JIT ou liées. Seul le code PTX ou les objets binaires précompilés peuvent être liés au moment de l'exécution par le pilote. – talonmies

+0

@talonmies: Oui, ils sont du code PTX. C'était une faute de frappe dans la question. – SonOfSun

Répondre

4

Je ne l'avais jamais écrit une seule ligne de code Java jusqu'à il y a 30 minutes, et encore moins utilisé JCUDA avant, mais une traduction en ligne par ligne presque littérale du code C++ natif que je vous ai donné here semble fonctionner parfaitement:

import static jcuda.driver.JCudaDriver.*; 
import java.io.*; 
import jcuda.*; 
import jcuda.driver.*; 

public class JCudaRuntimeTest 
{ 
    public static void main(String args[]) 
    { 
     JCudaDriver.setExceptionsEnabled(true); 

     cuInit(0); 
     CUdevice device = new CUdevice(); 
     cuDeviceGet(device, 0); 
     CUcontext context = new CUcontext(); 
     cuCtxCreate(context, 0, device); 

     CUlinkState linkState = new CUlinkState(); 
     JITOptions jitOptions = new JITOptions(); 
     cuLinkCreate(jitOptions, linkState); 

     String ptxFileName2 = "test_function.ptx"; 
     String ptxFileName1 = "test_kernel.ptx"; 

     cuLinkAddFile(linkState, CUjitInputType.CU_JIT_INPUT_PTX, ptxFileName2, jitOptions); 
     cuLinkAddFile(linkState, CUjitInputType.CU_JIT_INPUT_PTX, ptxFileName1, jitOptions); 

     long sz[] = new long[1]; 
     Pointer image = new Pointer(); 
     cuLinkComplete(linkState, image, sz); 
     System.out.println("Pointer: " + image); 
     System.out.println("CUBIN size: " + sz[0]); 

     CUmodule module = new CUmodule(); 
     cuModuleLoadDataEx(module, image, 0, new int[0], Pointer.to(new int[0])); 
     cuLinkDestroy(linkState); 

     CUfunction functionKernel = new CUfunction(); 
     String kernelname = "_Z6kernelPfS_S_S_"; 
     cuModuleGetFunction(functionKernel, module, kernelname); 
     System.out.println("Function: " + functionKernel); 
    } 
} 

qui fonctionne comme ceci:

> nvcc -ptx -arch=sm_21 test_function.cu 
test_function.cu 

> nvcc -ptx -arch=sm_21 test_kernel.cu 
test_kernel.cu 

> javac -cp ".;jcuda-0.7.0a.jar" JCudaRuntimeTest.java 
> java -cp ".;jcuda-0.7.0a.jar" JCudaRuntimeTest 
Pointer: Pointer[nativePointer=0xa5a13a8,byteOffset=0] 
CUBIN size: 5924 
Function: CUfunction[nativePointer=0xa588160] 

la clé ici semble être d'utiliser cuModuleLoadDataEx, faisant remarquer que les valeurs de retour de cuLinkComplete sont un pointeur de système au cubin lié et la taille de l'imag e retourné comme long[]. Selon le code C++, le pointeur est simplement passé directement au chargement des données du module. En guise de dernier commentaire, il aurait été beaucoup plus simple et plus facile si vous aviez posté un bon dossier de repro que l'on pouvait directement pirater, plutôt que de me faire apprendre les rudiments de JCUDA et de Java avant de pouvoir créer un utile repro cas et le faire fonctionner. La documentation pour JCUDA est basique, mais complète, et par rapport à l'exemple C++ déjà fourni, il n'a fallu que quelques minutes de lecture pour voir comment faire.

+0

Vous ne m'avez rien laissé à dire .. :) Vous êtes le meilleur ... Je veux dire .. "Je n'avais jamais écrit une seule ligne de code Java jusqu'à il y a 30 minutes, encore moins utilisé JCUDA avant .." m'a fait tellement sensationnel et excité ..! Je l'ai testé et exécuté dans le cadre et tout va bien .. :) Et vous avez raison sur les documentations en JCuda, je ne sais pas pourquoi je n'ai pas utilisé celui-ci, peut-être parce qu'il a été dit "c'est à peine possible de transmettre correctement les valeurs d'option requises pour cette méthode. " et m'a fait désespéré à ce sujet. Encore une fois, talonmies, merci ... :) – SonOfSun

+0

En effet, super boulot! (Je suis le gars JCuda, et je ne savais pas si c'était possible non plus (et je ne pouvais pas le tester ATM): -o). Super de voir que vous pourriez nous aider si vite et que ça marche! – Marco13