En primer lugar, debe tener en cuenta el hecho de que CUDA no hará que los cálculos sean más rápidos de forma automática. Por un lado, porque la programación de GPU es un arte, y puede ser muy, muy difícil hacerlo bien . Por otro lado, porque las GPU son adecuadas solo para ciertos tipos de cálculos.
Esto puede sonar confuso, porque básicamente puedes calcular cualquier cosa en la GPU. El punto clave es, por supuesto, si logrará una buena aceleración o no. La clasificación más importante aquí es si un problema es tarea paralela o datos paralelos . El primero se refiere, en términos generales, a problemas en los que varios subprocesos están trabajando en sus propias tareas, de manera más o menos independiente. El segundo se refiere a problemas en los que muchos subprocesos hacen lo mismo , pero en diferentes partes de los datos.
Este último es el tipo de problema en el que las GPU son buenas: tienen muchos núcleos y todos los núcleos hacen lo mismo, pero operan en diferentes partes de los datos de entrada.
Usted mencionó que tiene "matemática simple pero con gran cantidad de datos". Aunque esto puede sonar como un problema perfectamente paralelo a los datos y, por lo tanto, como si fuera adecuado para una GPU, hay otro aspecto a considerar: las GPU son ridículamente rápidas en términos de potencia computacional teórica (FLOPS, operaciones de punto flotante por segundo). Pero a menudo se ven limitados por el ancho de banda de la memoria.
Esto lleva a otra clasificación de problemas. Es decir, si los problemas están vinculados a la memoria o al cálculo .
El primero se refiere a problemas en los que el número de instrucciones que se realizan para cada elemento de datos es bajo. Por ejemplo, considere una suma de vectores paralelos: tendrá que leer dos elementos de datos, luego realizar una sola suma y luego escribir la suma en el vector de resultados. No verá una aceleración al hacer esto en la GPU, porque la única adición no compensa los esfuerzos de lectura / escritura de la memoria.
El segundo término, "límite de cálculo", se refiere a problemas donde el número de instrucciones es alto en comparación con el número de lecturas / escrituras de memoria. Por ejemplo, considere una multiplicación de matriz: el número de instrucciones será O (n ^ 3) cuando n es el tamaño de la matriz. En este caso, uno puede esperar que la GPU supere a una CPU en un determinado tamaño de matriz. Otro ejemplo podría ser cuando se realizan muchos cálculos trigonométricos complejos (seno / coseno, etc.) en "pocos" elementos de datos.
Como regla general: puede suponer que leer / escribir un elemento de datos de la memoria de la GPU "principal" tiene una latencia de aproximadamente 500 instrucciones ...
Por lo tanto, otro punto clave para el rendimiento de las GPU es la localidad de los datos : si tiene que leer o escribir datos (y en la mayoría de los casos, deberá hacerlo ;-)), entonces debe asegurarse de que los datos se mantengan tan cerca como sea posible. posible a los núcleos de GPU. Por lo tanto, las GPU tienen ciertas áreas de memoria (denominadas "memoria local" o "memoria compartida") que generalmente tienen un tamaño de unos pocos KB, pero son particularmente eficientes para los datos que están a punto de participar en un cálculo.
Entonces, para enfatizar esto nuevamente: la programación de GPU es un arte, que solo está remotamente relacionado con la programación paralela en la CPU. Cosas como subprocesos en Java, con toda la infraestructura de concurrencia como ThreadPoolExecutors
, ForkJoinPools
etc. , pueden dar la impresión de que solo tiene que dividir su trabajo de alguna manera y distribuirlo entre varios procesadores. En la GPU, puede encontrar desafíos en un nivel mucho más bajo: ocupación, presión de registro, presión de memoria compartida, fusión de memoria ... solo por nombrar algunos.
Sin embargo, cuando tiene que resolver un problema de cómputo de datos en paralelo, la GPU es el camino a seguir.
Una observación general: Su pedido específico de CUDA. Pero le recomiendo que también eche un vistazo a OpenCL. Tiene varias ventajas. En primer lugar, es un estándar de la industria abierto e independiente del proveedor, y hay implementaciones de OpenCL de AMD, Apple, Intel y NVIDIA. Además, hay un soporte mucho más amplio para OpenCL en el mundo Java. El único caso en el que prefiero conformarme con CUDA es cuando desea usar las bibliotecas de tiempo de ejecución CUDA, como CUFFT para FFT o CUBLAS para BLAS (operaciones de matriz / vector). Aunque existen enfoques para proporcionar bibliotecas similares para OpenCL, no se pueden usar directamente desde Java, a menos que cree sus propios enlaces JNI para estas bibliotecas.
También puede resultarle interesante escuchar que en octubre de 2012, el grupo OpenJDK HotSpot inició el proyecto "Sumatra": http://openjdk.java.net/projects/sumatra/ . El objetivo de este proyecto es proporcionar soporte de GPU directamente en la JVM, con soporte del JIT. El estado actual y los primeros resultados se pueden ver en su lista de correo en http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev
Sin embargo, hace un tiempo, recopilé algunos recursos relacionados con "Java en la GPU" en general. Resumiré esto nuevamente aquí, sin ningún orden en particular.
( Descargo de responsabilidad : soy el autor de http://jcuda.org/ y http://jocl.org/ )
(Byte) traducción de código y generación de código OpenCL:
https://github.com/aparapi/aparapi : una biblioteca de código abierto creada y mantenida activamente por AMD. En una clase especial "Kernel", uno puede anular un método específico que debe ejecutarse en paralelo. El código de bytes de este método se carga en tiempo de ejecución utilizando un lector de código de bytes propio. El código se traduce en código OpenCL, que luego se compila utilizando el compilador OpenCL. El resultado se puede ejecutar en el dispositivo OpenCL, que puede ser una GPU o una CPU. Si la compilación en OpenCL no es posible (o no hay OpenCL disponible), el código aún se ejecutará en paralelo, utilizando un Thread Pool.
https://github.com/pcpratts/rootbeer1 : una biblioteca de código abierto para convertir partes de Java en programas CUDA. Ofrece interfaces dedicadas que pueden implementarse para indicar que una determinada clase debe ejecutarse en la GPU. A diferencia de Aparapi, intenta serializar automáticamente los datos "relevantes" (es decir, ¡la parte relevante completa del gráfico de objetos!) En una representación adecuada para la GPU.
https://code.google.com/archive/p/java-gpu/ : una biblioteca para traducir código Java anotado (con algunas limitaciones) en código CUDA, que luego se compila en una biblioteca que ejecuta el código en la GPU. La Biblioteca se desarrolló en el contexto de una tesis doctoral, que contiene información de fondo profunda sobre el proceso de traducción.
https://github.com/ochafik/ScalaCL : enlaces Scala para OpenCL. Permite procesar colecciones especiales de Scala en paralelo con OpenCL. Las funciones que se invocan en los elementos de las colecciones pueden ser funciones Scala habituales (con algunas limitaciones) que luego se traducen en núcleos OpenCL.
Extensiones de idioma
http://www.ateji.com/px/index.html : una extensión de lenguaje para Java que permite construcciones paralelas (por ejemplo, paralelas para bucles, estilo OpenMP) que luego se ejecutan en la GPU con OpenCL. Desafortunadamente, este proyecto muy prometedor ya no se mantiene.
http://www.habanero.rice.edu/Publications.html (JCUDA): una biblioteca que puede traducir código Java especial (llamado código JCUDA) en código Java y CUDA-C, que luego se puede compilar y ejecutar en el GPU Sin embargo, la biblioteca no parece estar disponible públicamente.
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : extensión de lenguaje Java para construcciones OpenMP, con un backend CUDA
Bibliotecas de enlace Java OpenCL / CUDA
https://github.com/ochafik/JavaCL : enlaces de Java para OpenCL: una biblioteca OpenCL orientada a objetos, basada en enlaces de bajo nivel autogenerados
http://jogamp.org/jocl/www/ : enlaces de Java para OpenCL: una biblioteca OpenCL orientada a objetos, basada en enlaces de bajo nivel autogenerados
http://www.lwjgl.org/ : enlaces de Java para OpenCL: enlaces de bajo nivel autogenerados y clases de conveniencia orientadas a objetos
http://jocl.org/ : enlaces de Java para OpenCL: enlaces de bajo nivel que son una asignación 1: 1 de la API original de OpenCL
http://jcuda.org/ : enlaces de Java para CUDA: enlaces de bajo nivel que son una asignación 1: 1 de la API de CUDA original
Diverso
http://sourceforge.net/projects/jopencl/ : enlaces de Java para OpenCL. Parece que ya no se mantiene desde 2010
http://www.hoopoe-cloud.com/ : enlaces de Java para CUDA. Parece que ya no se mantiene