Utilisation de Java avec les GPU de Nvidia (cuda)
je travaille sur un projet d'entreprise qui se fait en java et nécessite une énorme puissance de calcul pour calculer les marchés d'affaires. Mathématiques simples, mais avec une énorme quantité de données.
nous avons commandé quelques gpu cuda pour l'essayer et comme Java n'est pas supporté par Cuda, je me demande par où commencer. Dois-je construire une interface JNI? Dois-je utiliser JCUDA ou y a-t-il d'autres moyens?
je n'ai pas d'expérience dans ce domaine et je voudrais si quelqu'un pouvait me diriger vers quelque chose pour que je puisse commencer à faire des recherches et apprendre.
2 réponses
tout d'abord, vous devez être conscient du fait que CUDA ne fera pas automatiquement des calculs plus rapides. D'une part, parce que la programmation GPU est un art, et il peut être très, très difficile de l'obtenir droit . D'autre part, parce que les GPU sont bien adaptés seulement pour certains types de calculs.
cela peut sembler confus, parce que vous pouvez essentiellement calculer n'importe quoi sur le GPU. Le point clé est, bien sûr, si vous atteindrez une bonne accélération ou non. La classification la plus importante ici est de savoir si un problème est parallèle de tâche ou parallèle de données . La première se réfère, grosso modo, à des problèmes où plusieurs fils travaillent sur leurs propres tâches, plus ou moins indépendamment. Le second fait référence à des problèmes où beaucoup fils sont tous faisant la même - mais sur les différentes parties des données.
ce dernier est le type de problème que les GPU sont bons à: ils ont beaucoup noyaux, et tous les noyaux font la même chose, mais fonctionnent sur différentes parties des données d'entrée.
Vous avez mentionné que vous avez "mathématiques simples, mais avec l'énorme quantité de données". Bien que cela puisse sembler être un problème parfaitement parallèle aux données et donc comme s'il était bien adapté à un GPU, il y a un autre aspect à considérer: les GPU sont ridiculement rapide en termes de puissance de calcul théorique (FLOPS, opérations en virgule flottante par seconde). Mais ils sont souvent étouffés par la bande passante mémoire.
Cela conduit à une autre classification des problèmes. À savoir si les problèmes sont lié à la mémoire ou lié au calcul .
le premier fait référence à des problèmes où le nombre d'instructions qui sont faites pour chaque élément de données est faible. Par exemple, considérez un ajout de vecteur parallèle: vous devrez lire deux éléments de données, puis effectuer un ajout unique, et ensuite écrire la somme dans le vecteur de résultat. Vous ne verrez pas d'accélération lorsque vous faites cela sur le GPU, parce que l'ajout unique ne compense pas les efforts de lecture/écriture de la mémoire.
le deuxième terme, "lié par calcul", se réfère à des problèmes où le nombre d'instructions est élevé comparé au nombre de mémoires lit/écrit. Par exemple, considérons une multiplication matricielle: le nombre d'instructions sera O(N^3) quand n est la taille de la matrice. Dans ce cas, on peut s'attendre à ce que le GPU surpasse un CPU à une certaine taille de matrice. Un autre exemple pourrait être lorsque de nombreux calculs trigonométriques complexes (sinus, cosinus, etc.) sont effectués sur "peu" d'éléments de données.
comme une règle empirique: vous pouvez supposer que la lecture / écriture d'un élément de données de la la mémoire GPU "principale" a une latence d'environ 500 instructions....
par conséquent, un autre point clé pour la performance de GPUs est localité de données : si vous devez lire ou écrire des données (et dans la plupart des cas, vous devrez; -)), alors vous devez vous assurer que les données sont maintenues aussi près que possible des noyaux GPU. Les gpu ont donc certaines zones de mémoire (appelé "mémoire locale" ou de "mémoire partagée") qui est habituellement seulement quelques KO, mais particulièrement efficace pour les données qui sont sur le point d'être impliqués dans un calcul.
donc pour souligner encore ceci: la programmation GPU est un art, qui n'est relié qu'à distance à la programmation parallèle sur le CPU. Des choses comme les Threads en Java, avec toute l'infrastructure de concurrence comme ThreadPoolExecutors
, ForkJoinPools
, etc. pourrait donner l'impression que vous avez juste à diviser votre travail en quelque sorte à distribuer entre plusieurs processeurs. Sur le GPU, vous pouvez rencontrer des défis sur un beaucoup plus bas niveau: occupation, pression de registre, pression de mémoire partagée, coalescence de mémoire ... juste pour en nommer quelques-uns.
cependant, quand vous avez un problème de calcul lié à des données parallèles à résoudre, le GPU est la voie à suivre.
une remarque générale: vous avez spécifiquement demandé CUDA. Mais je vous recommande vivement D'avoir aussi un oeil à OpenCL. Elle présente plusieurs avantages. Tout d'abord, c'est une norme de l'industrie ouverte, indépendante du vendeur, et il y a des implémentations D'OpenCL par AMD, Apple, Intel et NVIDIA. De plus, il existe un support beaucoup plus large pour OpenCL dans le monde Java. Le seul cas où je préfère me contenter de CUDA est quand vous voulez utiliser les bibliothèques d'exécution de CUDA, comme CUFFT pour FFT ou CUBLAS pour BLAS (opérations matricielles/vectorielles). Bien qu'il existe des approches pour fournir des bibliothèques similaires pour OpenCL, elles ne peuvent pas être utilisées directement du côté Java, à moins que vous ne créiez vos propres fixations JNI pour ces bibliothèques.
"vous pourriez également trouver intéressant d'entendre qu'en octobre 2012, le groupe Hotspot OpenJDK a commencé le projet" Sumatra": http://openjdk.java.net/projects/sumatra / . L'objectif de ce projet est de fournir un soutien GPU directement dans la JVM, avec le soutien de la JIT. L'état actuel et les premiers résultats peuvent être vus dans leur liste de diffusion au http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev
cependant, il y a un certain temps, j'ai rassemblé quelques ressources liées à "Java sur le GPU" en général. Je vais les résumer à nouveau ici, sans ordre particulier.
( clause de non-responsabilité :je suis l'auteur de http://jcuda.org / et http://jocl.org / )
(Octets)code traduction et génération de code OpenCL:
https://github.com/aparapi/aparapi : une bibliothèque libre créée et gérée activement par AMD. Dans une classe spéciale" Kernel", on peut outrepasser une méthode spécifique qui doit être exécutée en parallèle. Le code octet de cette méthode est chargé à l'exécution en utilisant un lecteur de bytecode propre. Le code est traduit en code OpenCL, qui est ensuite compilé à l'aide du compilateur OpenCL. Le résultat peut alors être exécuté sur le dispositif OpenCL, qui peut être un GPU ou un CPU. Si la compilation dans OpenCL n'est pas possible (ou si OpenCL n'est pas disponible), le code sera quand même exécuté en parallèle, en utilisant un Pool de threads.
https://github.com/pcpratts/rootbeer1 : une bibliothèque libre pour convertir des parties de Java en programmes CUDA. Il offre des interfaces dédiées qui peuvent être implémentées pour indiquer qu'une certaine classe doit être exécutée sur le GPU. Dans contrairement à Aparapi, il essaie de sérialiser automatiquement les données "pertinentes" (c'est-à-dire la partie pertinente complète du graphe d'objet!) dans une représentation adaptée au GPU.
https://code.google.com/archive/p/java-gpu / : une bibliothèque pour traduire du code Java annoté (avec quelques limitations) en code CUDA, qui est ensuite compilé dans une bibliothèque qui exécute le code sur le GPU. La bibliothèque a été développée dans le cadre D'un doctorat thèse, qui contient des informations de fond profondes sur le processus de traduction.
https://github.com/ochafik/ScalaCL : Scala bindings for OpenCL. Permet aux collections spéciales Scala d'être traitées en parallèle avec OpenCL. Les fonctions qui sont appelées sur les éléments des collections peuvent être des fonctions Scala habituelles (avec quelques limitations) qui sont ensuite traduites en noyaux OpenCL.
extensions linguistiques
http://www.ateji.com/px/index.html : une extension de langage pour Java qui permet des constructions parallèles (par exemple parallèle pour les boucles, style OpenMP) qui sont ensuite exécutées sur le GPU avec OpenCL. Malheureusement, ce projet très prometteur n'est plus maintenu.
http://www.habanero.rice.edu/Publications.html (JCUDA): une bibliothèque qui peut traduire du code Java spécial (appelé code JCUDA) en Code Java - et CUDA-C, qui peut ensuite être compilé et exécuté sur le GPU. Cependant, la bibliothèque ne semble pas être accessible au public.
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : extension du langage Java pour pour OpenMP constructions, avec un CUDA backend
Java OpenCL/CUDA binding libraries
https://github.com/ochafik/JavaCL : Java liaisons pour OpenCL: Une orientée objet OpenCL bibliothèque, basé sur l'auto-généré à faible niveau de liaisons
http://jogamp.org/jocl/www/ : liaisons Java pour OpenCL: une bibliothèque OpenCL orientée objet, basée sur des liaisons de bas niveau générées automatiquement
http://www.lwjgl.org / : fixations Java pour OpenCL: Fixations de bas niveau générées automatiquement et classes de commodité orientées objet
http://jocl.org / : les fixations Java pour OpenCL: les fixations de bas niveau qui sont un mappage 1:1 de L'API OpenCL d'origine
http://jcuda.org / : fixations Java pour CUDA: Fixations de bas niveau qui sont une cartographie 1:1 de L'API CUDA originale
Divers
http://sourceforge.net/projects/jopencl / : Java bindings for OpenCL. Semblent être n'est plus maintenu depuis 2010
http://www.hoopoe-cloud.com / : Java bindings for CUDA. Ne semble plus être maintenu
je commencerais par utiliser un des projets là-bas pour Java et CUDA: http://www.jcuda.org/