Prima di tutto, dovresti essere consapevole del fatto che CUDA non renderà automaticamente i calcoli più veloci. Da un lato, perché la programmazione GPU è un'arte e può essere molto, molto impegnativo, farlo nel modo giusto . D'altra parte, poiché le GPU sono adatte solo per determinati tipi di calcoli.
Questo può sembrare confuso, perché puoi praticamente calcolare qualsiasi cosa sulla GPU. Il punto chiave è, ovviamente, se raggiungerai una buona velocità o no. La classificazione più importante qui è se un problema è il task parallelo o il parallelismo dei dati . Il primo si riferisce, approssimativamente, a problemi in cui diversi thread stanno lavorando ai propri compiti, più o meno in modo indipendente. Il secondo si riferisce a problemi in cui molti thread fanno tutti lo stesso , ma su parti diverse dei dati.
Quest'ultimo è il tipo di problema in cui le GPU sono brave: hanno molti core e tutti i core fanno lo stesso, ma operano su parti diverse dei dati di input.
Hai detto che hai "matematica semplice ma con un'enorme quantità di dati". Sebbene questo possa sembrare un problema perfettamente parallelo ai dati e quindi adatto per una GPU, c'è un altro aspetto da considerare: le GPU sono ridicolmente veloci in termini di potenza computazionale teorica (FLOPS, Floating Point Operations al secondo). Ma sono spesso limitati dalla larghezza di banda della memoria.
Questo porta ad un'altra classificazione dei problemi. Vale a dire se i problemi sono associati alla memoria o ai calcoli .
Il primo si riferisce ai problemi in cui il numero di istruzioni eseguite per ciascun elemento di dati è basso. Ad esempio, considera un'aggiunta vettoriale parallela: dovrai leggere due elementi di dati, quindi eseguire una singola aggiunta e quindi scrivere la somma nel vettore risultato. Non vedrai uno speedup quando lo fai sulla GPU, perché la singola aggiunta non compensa gli sforzi di leggere / scrivere la memoria.
Il secondo termine, "limite di calcolo", si riferisce a problemi in cui il numero di istruzioni è elevato rispetto al numero di letture / scritture di memoria. Ad esempio, considera una moltiplicazione di matrici: il numero di istruzioni sarà O (n ^ 3) quando n è la dimensione della matrice. In questo caso, ci si può aspettare che la GPU supererà una CPU con una certa dimensione della matrice. Un altro esempio potrebbe essere quando molti calcoli trigonometrici complessi (seno / coseno ecc.) Vengono eseguiti su "pochi" elementi di dati.
Come regola generale: si può presumere che la lettura / scrittura di un elemento di dati dalla memoria GPU "principale" abbia una latenza di circa 500 istruzioni ....
Pertanto, un altro punto chiave per le prestazioni delle GPU è la localizzazione dei dati : se devi leggere o scrivere dati (e nella maggior parte dei casi, dovrai ;-)), allora dovresti assicurarti che i dati siano mantenuti il più vicino possibile possibile ai core della GPU. Le GPU hanno quindi determinate aree di memoria (denominate "memoria locale" o "memoria condivisa") che di solito hanno solo pochi KB, ma sono particolarmente efficienti per i dati che stanno per essere coinvolti in un calcolo.
Quindi, per sottolineare ancora una volta: la programmazione GPU è un'arte, che è solo lontanamente correlata alla programmazione parallela sulla CPU. Cose come Thread in Java, con tutte le infrastrutture di concorrenza come ThreadPoolExecutors
, ForkJoinPools
ecc. Potrebbero dare l'impressione che devi solo dividere il tuo lavoro in qualche modo e distribuirlo tra più processori. Sulla GPU, potresti incontrare sfide a un livello molto più basso: occupazione, pressione del registro, pressione della memoria condivisa, coalescenza della memoria ... solo per citarne alcuni.
Tuttavia, quando si deve risolvere un problema parallelo ai dati e legato al calcolo, la GPU è la strada da percorrere.
Un'osservazione generale: hai chiesto specificamente CUDA. Ma ti consiglio vivamente di dare un'occhiata anche a OpenCL. Ha diversi vantaggi. Prima di tutto, è uno standard industriale aperto indipendente dal fornitore e ci sono implementazioni di OpenCL di AMD, Apple, Intel e NVIDIA. Inoltre, esiste un supporto molto più ampio per OpenCL nel mondo Java. L'unico caso in cui preferirei accontentarmi di CUDA è quando si desidera utilizzare le librerie di runtime CUDA, come CUFFT per FFT o CUBLAS per BLAS (operazioni Matrix / Vector). Sebbene esistano approcci per fornire librerie simili per OpenCL, non possono essere utilizzate direttamente dal lato Java, a meno che non si creino i propri collegamenti JNI per queste librerie.
Potresti anche trovare interessante sapere che nell'ottobre 2012, il gruppo OpenJDK HotSpot ha avviato il progetto "Sumatra": http://openjdk.java.net/projects/sumatra/ . L'obiettivo di questo progetto è fornire supporto GPU direttamente nella JVM, con il supporto della JIT. Lo stato corrente e i primi risultati possono essere visualizzati nella loro mailing list su http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev
Tuttavia, qualche tempo fa, ho raccolto alcune risorse relative a "Java sulla GPU" in generale. Le riassumerò di nuovo qui, in nessun ordine particolare.
( Dichiarazione di non responsabilità : sono l'autore di http://jcuda.org/ e http://jocl.org/ )
(Byte) traduzione del codice e generazione del codice OpenCL:
https://github.com/aparapi/aparapi : una libreria open source creata e gestita attivamente da AMD. In una speciale classe "Kernel", si può sovrascrivere un metodo specifico che dovrebbe essere eseguito in parallelo. Il codice byte di questo metodo viene caricato in fase di esecuzione utilizzando un proprio lettore bytecode. Il codice viene tradotto in codice OpenCL, che viene quindi compilato utilizzando il compilatore OpenCL. Il risultato può quindi essere eseguito sul dispositivo OpenCL, che può essere una GPU o una CPU. Se la compilazione in OpenCL non è possibile (o non è disponibile OpenCL), il codice verrà comunque eseguito in parallelo, utilizzando un pool di thread.
https://github.com/pcpratts/rootbeer1 : una libreria open source per convertire parti di Java in programmi CUDA. Offre interfacce dedicate che possono essere implementate per indicare che una determinata classe deve essere eseguita sulla GPU. A differenza di Aparapi, tenta di serializzare automaticamente i dati "rilevanti" (ovvero la parte rilevante completa del grafico oggetto!) In una rappresentazione adatta alla GPU.
https://code.google.com/archive/p/java-gpu/ : una libreria per la traduzione di codice Java annotato (con alcune limitazioni) in codice CUDA, che viene quindi compilato in una libreria che esegue il codice sulla GPU. La Biblioteca è stata sviluppata nel contesto di una tesi di dottorato, che contiene profonde informazioni di base sul processo di traduzione.
https://github.com/ochafik/ScalaCL : attacchi Scala per OpenCL. Consente l'elaborazione di raccolte Scala speciali in parallelo con OpenCL. Le funzioni che vengono chiamate sugli elementi delle raccolte possono essere le normali funzioni Scala (con alcune limitazioni) che vengono poi tradotte in kernel OpenCL.
Estensioni di lingua
http://www.ateji.com/px/index.html : un'estensione di linguaggio per Java che consente costrutti paralleli (ad es. parallelo per loop, stile OpenMP) che vengono quindi eseguiti sulla GPU con OpenCL. Sfortunatamente, questo progetto molto promettente non viene più mantenuto.
http://www.habanero.rice.edu/Publications.html (JCUDA): una libreria in grado di tradurre codice Java speciale (chiamato codice JCUDA) in codice Java e CUDA-C, che può quindi essere compilato ed eseguito sul GPU. Tuttavia, la libreria non sembra essere disponibile al pubblico.
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : estensione del linguaggio Java per costrutti OpenMP, con un backend CUDA
Librerie di associazione Java OpenCL / CUDA
https://github.com/ochafik/JavaCL : collegamenti Java per OpenCL: una libreria OpenCL orientata agli oggetti, basata su collegamenti di basso livello generati automaticamente
http://jogamp.org/jocl/www/ : collegamenti Java per OpenCL: una libreria OpenCL orientata agli oggetti, basata su collegamenti di basso livello generati automaticamente
http://www.lwjgl.org/ : Collegamenti Java per OpenCL: collegamenti di basso livello generati automaticamente e classi di convenienza orientate agli oggetti
http://jocl.org/ : collegamenti Java per OpenCL: collegamenti di basso livello che sono una mappatura 1: 1 dell'API OpenCL originale
http://jcuda.org/ : Collegamenti Java per CUDA: collegamenti di basso livello che sono una mappatura 1: 1 dell'API CUDA originale
miscellaneo
http://sourceforge.net/projects/jopencl/ : collegamenti Java per OpenCL. Sembra non essere più mantenuto dal 2010
http://www.hoopoe-cloud.com/ : collegamenti Java per CUDA. Sembra non essere più mantenuto