Utilisation de Java avec les GPU Nvidia (CUDA)


Je travaille sur un projet d'entreprise qui se fait en Java, et il a besoin d'une énorme puissance de calcul pour calculer les marchés commerciaux. Mathématiques simples, mais avec une énorme quantité de données.

Nous avons commandé des GPU CUDA pour l'essayer et puisque Java n'est pas supporté par CUDA, je me demande par où commencer. Dois-je construire une interface JNI? Dois-je utiliser JCUDA ou existe-t-il d'autres moyens?

Je n'ai pas d'expérience dans ce domaine et j'aimerais que quelqu'un puisse me diriger vers quelque chose alors je peut commencer la recherche et l'apprentissage.

Author: Peter Mortensen, 2014-04-04

5 answers

Tout d'abord, vous devez être conscient du fait que CUDA n'accélérera pas automatiquement les calculs. D'une part, parce que la programmation GPU est un art, et il peut être très, très difficile de l'obtenir correctement. D'autre part, parce que les GPU ne conviennent que pour certains types de calculs.

Cela peut sembler déroutant, car vous pouvez essentiellement calculer n'importe quoi sur le GPU. Le point clé est, bien sûr, si vous obtiendrez une bonne accélération ou pas. La classification la plus importante ici est de savoir si un problème est task parallel ou data parallel. Le premier se réfère, grosso modo, à des problèmes où plusieurs threads travaillent sur leurs propres tâches, plus ou moins indépendamment. Le second fait référence à des problèmes où de nombreuxthreads sont faisant tous la même chose - mais sur différentes parties des données.

Ce dernier est le genre de problème pour lequel les GPU sont bons: Ils ont beaucoup de cœurs, et tous les cœurs font de même, mais fonctionnent sur différentes parties des données d'entrée.

Vous avez mentionné que vous avez "des mathématiques simples mais avec une énorme quantité de données". Bien que cela puisse sembler un problème parfaitement parallèle aux données et donc bien adapté à un GPU, il y a un autre aspect à considérer: les GPU sont ridiculement rapides en termes de puissance de calcul théorique (FLOPS, Opérations en virgule flottante par seconde). Mais ils sont souvent étranglés par la mémoire passante.

Cela conduit à une autre classification des problèmes. À savoir si les problèmes sont liés à la mémoire ou liés au calcul .

Le premier fait référence aux problèmes où le nombre d'instructions effectuées pour chaque élément de données est faible. Par exemple, considérons une addition de vecteur parallèle: Vous devrez lire deux éléments de données, puis effectuer une seule addition, puis écrire la somme dans le vecteur de résultat. Vous ne verrez pas d'accélération quand faire cela sur le GPU, car l'ajout unique ne compense pas les efforts de lecture/écriture de la mémoire.

Le deuxième terme, "compute bound", fait référence aux problèmes où le nombre d'instructions est élevé par rapport au nombre de lectures/écritures en mémoire. Par exemple, considérons une multiplication matricielle: Le nombre d'instructions sera O(n^3) lorsque n est la taille de la matrice. Dans ce cas, on peut s'attendre à ce que le GPU surpasse un PROCESSEUR à une certaine taille de matrice. Un Autre un exemple pourrait être lorsque de nombreux calculs trigonométriques complexes (sinus/cosinus, etc.) sont effectués sur "quelques" éléments de données.

En règle générale: Vous pouvez supposer que la lecture/écriture d'un élément de données à partir de la mémoire GPU "principale" a une latence d'environ 500 instructions....

Par conséquent, un autre point clé pour les performances des GPU 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 conservées aussi près que possible des cœurs GPU. Les GPU ont donc certaines zones de mémoire (appelées "mémoire locale" ou "mémoire partagée") qui ne sont généralement que de quelques Ko, mais particulièrement efficaces pour les données sur le point d'être impliquées dans un calcul.

Donc pour le souligner encore une fois: la programmation GPU est un art, qui n'est lié qu'à distance à la programmation parallèle sur le CPU. Des choses comme des 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 et le distribuer entre plusieurs processeurs. Sur le GPU, vous pouvez rencontrer des défis à un niveau beaucoup plus bas: Occupation, pression de registre, pression de mémoire partagée, fusion de la mémoire ... juste pour en nommer quelques-uns.

Cependant, lorsque vous avez un problème parallèle aux données et lié au calcul à résoudre, le GPU est la voie à suivre.


Une remarque générale: Votre demande spécifique pour CUDA. Mais je vous recommande fortement de jeter un œil à OpenCL. Il a plusieurs avantages. Tout d'abord, c'est un standard industriel ouvert et indépendant du fournisseur, et il existe 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 lorsque vous souhaitez utiliser les bibliothèques d'exécution 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 directement être utilisé du côté Java, sauf si vous créez vos propres liaisons JNI pour ces bibliothèques.


Vous pourriez aussi trouver intéressant d'entendre qu'en octobre 2012, le groupe OpenJDK HotSpot a lancé le projet "Sumatra": http://openjdk.java.net/projects/sumatra / . L'objectif de ce projet est de fournir un support GPU directement dans la JVM, avec le support du JIT. L'état actuel et les premiers résultats peuvent être vus dans leur liste de diffusion à http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev


Cependant, il y a quelque temps, j'ai collecté des ressources liées à "Java sur le GPU" en général. Je vais les résumer à nouveau ici, sans ordre particulier.

(Avertissement: je suis l'auteur de http://jcuda.org/ et http://jocl.org/ )

Traduction de code(octet) et génération de code OpenCL:

Https://github.com/aparapi/aparapi {[56] } : Une source ouverte bibliothèque créée et activement maintenue par AMD. Dans une classe spéciale "Noyau", on peut remplacer une méthode spécifique qui doit être exécutée en parallèle. Le pseudo-code de cette méthode est chargé lors de l'exécution à l'aide d'un bytecode lecteur. Le code est traduit en code OpenCL, qui est ensuite compilé à l'aide du compilateur OpenCL. Le résultat peut ensuite être exécuté sur le périphérique OpenCL, qui peut être un GPU ou un CPU. Si la compilation dans OpenCL n'est pas possible (ou si aucun OpenCL n'est disponible), le code sera toujours exécuté en parallèle, en utilisant un pool de threads.

Https://github.com/pcpratts/rootbeer1 : Une bibliothèque open-source 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. Contrairement à Aparapi, il essaie de sérialiser automatiquement les données "pertinentes" (c'est-à-dire la partie pertinente complète du graphique d'objet!) dans une représentation qui convient à la GPU.

Https://code.google.com/archive/p/java-gpu / : Une bibliothèque pour traduire le code Java annoté (avec certaines 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'une thèse de doctorat, qui contient des informations générales approfondies sur le processus de traduction.

Https://github.com/ochafik/ScalaCL : Liaisons Scala pour OpenCL. Permet aux collections Scala spéciales d'être traité 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 de langue

Http://www.ateji.com/px/index.html : Une extension de langage pour Java qui permet des constructions parallèles (par exemple parallel for loops, style OpenMP) qui sont ensuite exécutées sur le GPU avec OpenCL. Malheureusement, ce projet très prometteur, n'est plus exploité.

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 de langage Java pour les constructions OpenMP, avec un backend CUDA

Java Bibliothèques de liaison OpenCL/CUDA

Https://github.com/ochafik/JavaCL : 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://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 / : Liaisons Java pour OpenCL: Liaisons de bas niveau générées automatiquement et commodité orientée objet les classes

Http://jocl.org / : Liaisons Java pour OpenCL:Liaisons de bas niveau qui sont un mappage 1: 1 de l'API OpenCL d'origine

Http://jcuda.org / : Liaisons Java pour CUDA:Liaisons de bas niveau qui sont un mappage 1: 1 de l'API CUDA d'origine

Divers

Http://sourceforge.net/projects/jopencl/: Liaisons Java pour OpenCL. Semble ne plus être maintenu depuis 2010

Http://www.hoopoe-cloud.com/ : Liaisons Java pour CUDA. Semble ne plus être maintenu


 461
Author: Marco13, 2017-09-10 14:30:14

Je commencerais par utiliser l'un des projets pour Java et CUDA: http://www.jcuda.org/

 4
Author: JohnKlehm, 2014-04-04 16:34:02

De la recherche que j'ai faite, si vous ciblez les GPU Nvidia et avez décidé d'utiliser CUDA surOpenCL , j'ai trouvé trois façons d'utiliser l'API CUDA en java.

  1. JCuda (ou alternative)- http://www.jcuda.org / . Cela semble être la meilleure solution pour les problèmes sur lesquels je travaille. Beaucoup de bibliothèques telles que CUBLAS sont disponibles dans JCuda. Les noyaux sont toujours écrits en C cependant.
  2. Les interfaces JNI - JNI ne sont pas mes préférées pour écrire, mais sont très puissant et vous permettrait de faire tout ce que CUDA peut faire.
  3. JavaCPP - Cela vous permet essentiellement de créer une interface JNI en Java sans écrire de code C directement. Il y a un exemple ici: Quelle est la façon la plus simple d'exécuter du code CUDA en Java? de la façon de l'utiliser avec CUDA thrust. Pour moi, cela semble que vous pourriez aussi bien écrire une interface JNI.

Toutes ces réponses ne sont essentiellement que des moyens d'utiliser le code C/C++ en Java. Vous devriez vous demander pourquoi vous besoin d'utiliser Java et si vous ne pouvez pas le faire en C/C++ à la place.

Si vous aimez Java et savez comment l'utiliser et que vous ne voulez pas travailler avec toute la gestion des pointeurs et ce qui n'est pas fourni avec C/C++, JCuda est probablement la réponse. D'autre part, la bibliothèque CUDA Thrust et d'autres bibliothèques comme elle peuvent être utilisées pour faire beaucoup de la gestion des pointeurs en C/C++ et peut-être que vous devriez regarder cela.

Si vous aimez C/C++ et que la gestion des pointeurs ne vous dérange pas, mais qu'il existe d'autres contraintes vous forçant à utiliser Java, alors JNI pourrait être la meilleure approche. Cependant, si vos méthodes JNI ne sont que des wrappers pour les commandes du noyau, vous pouvez aussi bien utiliser JCuda.

Il existe quelques alternatives à JCuda telles que Cuda4J et Root Beer, mais celles-ci ne semblent pas être maintenues. Alors qu'au moment de la rédaction de ce JCuda prend en charge CUDA 10.1. quel est le SDK CUDA le plus à jour.

De plus, il existe quelques bibliothèques java qui utilisent CUDA, telles que deeplearning4j et Hadoop, cela peut être capable de faire ce que vous recherchez sans vous obliger à écrire directement du code du noyau. Je ne les ai pas trop regardés cependant.

 3
Author: David Griffin, 2020-04-02 01:47:59

Marco13 déjà fourni une excellente réponse.

Si vous cherchez un moyen d'utiliser le GPU sans implémenter les noyaux CUDA/OpenCL, je voudrais ajouter une référence aux finmath-lib-cuda-extensions (finmath-lib-gpu-extensions) http://finmath.net/finmath-lib-cuda-extensions / (avertissement: Je suis le mainteneur de ce projet).

Le projet fournit une implémentation de "classes vectorielles", pour être précis, une interface appelée RandomVariable, qui fournit des opérations arithmétiques et la réduction sur les vecteurs. Il existe des implémentations pour le CPU et le GPU. Il existe une implémentation utilisant la différenciation algorithmique ou des évaluations simples.

Les améliorations de performances sur le GPU sont actuellement petites (mais pour les vecteurs de taille 100.000, vous pouvez obtenir un facteur > 10 améliorations de performances). Cela est dû aux petites tailles de noyau. Cela s'améliorera dans une future version.

L'implémentation GPU utilise JCuda et JOCL et sont disponibles pour Nvidia et ATI Gpu.

La bibliothèque est Apache 2.0 et disponible via Maven Central.

 1
Author: Christian Fries, 2020-04-02 01:50:58

Il n'y a pas beaucoup d'informations sur la nature du problème et les données, si difficile à conseiller. Cependant, recommanderait d'évaluer la faisabilité d'autres solutions, qui peuvent être plus faciles à intégrer avec java et permet une mise à l'échelle horizontale et verticale. Le premier que je suggère de regarder est un moteur analytique open source appelé Apache Spark https://spark.apache.org / qui est disponible sur Microsoft Azure mais probablement sur d'autres fournisseurs IaaS cloud aussi. Si vous vous en tenez à impliquant votre GPU, la suggestion est de regarder d'autres bases de données analytiques prises en charge par GPU sur le marché qui correspondent au budget de votre organisation.

 0
Author: ben, 2020-10-17 22:46:35