Korzystanie z Java z GPU Nvidia (CUDA)

Pracuję nad projektem biznesowym, który jest wykonywany w Javie i potrzebuje ogromnej mocy obliczeniowej, aby obliczyć rynki biznesowe. Prosta matematyka, ale z ogromną ilością danych.

Zamówiliśmy kilka GPU CUDA, aby go wypróbować, a ponieważ Java nie jest obsługiwana przez CUDA, zastanawiam się, od czego zacząć. Czy powinienem zbudować interfejs JNI? Czy powinienem używać JCUDA czy są inne sposoby?

Nie mam doświadczenia w tej dziedzinie i chciałbym, aby ktoś mógł mnie do czegoś skierować, więc może rozpocząć badania i naukę.

Author: Peter Mortensen, 2014-04-04

5 answers

Przede wszystkim powinieneś być świadomy faktu, że CUDA nie będzie automagicznie wykonywać obliczeń szybciej. Z jednej strony, ponieważ programowanie GPU jest sztuką i może być bardzo, bardzo trudne, aby uzyskać to Prawo . Z drugiej strony, ponieważ GPU są dobrze dostosowane tylko do niektórych rodzajów obliczeń.

Może to zabrzmieć myląco, ponieważ możesz w zasadzie obliczyć cokolwiek na GPU. Najważniejsze jest oczywiście to, czy osiągniesz dobre przyspieszenie albo i nie. Najważniejszą klasyfikacją jest tutaj to, czy problemem jest task parallel czy data parallel. Pierwszy z nich odnosi się, z grubsza mówiąc, do problemów, w których kilka wątków pracuje nad własnymi zadaniami, mniej lub bardziej niezależnie. Drugi odnosi się do problemów, w których Wiele wątków robi to samo - ale w różnych częściach danych.

Ten ostatni jest rodzajem problemu, w którym GPU są dobre: mają Wiele Rdzeni, wszystkie rdzenie robią to samo, ale działają na różnych częściach danych wejściowych.

Wspomniałeś, że masz "prostą matematykę, ale z ogromną ilością danych". Chociaż może to brzmieć jak idealnie równoległy problem danych, a tym samym jak to było dobrze dostosowane do GPU, istnieje inny aspekt do rozważenia: GPU są śmiesznie szybkie pod względem teoretycznej mocy obliczeniowej (FLOPS, operacje zmiennoprzecinkowe na sekundę). Ale często są dławione przez pamięć przepustowość.

Prowadzi to do innej klasyfikacji problemów. Mianowicie, czy problemy są związane z pamięcią lub Oblicz związane.

Pierwszy odnosi się do problemów, w których liczba instrukcji wykonywanych dla każdego elementu danych jest niska. Na przykład, rozważmy dodanie wektora równoległego: musisz odczytać dwa elementy danych, następnie wykonać pojedyncze dodanie, a następnie zapisać sumę do wektora wynikowego. Nie zobaczysz przyspieszenia, gdy robi to na GPU, ponieważ pojedynczy dodatek nie rekompensuje wysiłków czytania / pisania pamięci.

Drugi termin, "compute bound", odnosi się do problemów, w których liczba instrukcji jest wysoka w porównaniu do liczby odczytów/zapisów pamięci. Na przykład, rozważmy mnożenie macierzy: Liczba instrukcji będzie O (N^3), Gdy n jest wielkością macierzy. W takim przypadku można się spodziewać, że GPU przewyższy procesor o określonej wielkości matrycy. Inny przykładem może być sytuacja, gdy wiele złożonych obliczeń trygonometrycznych (Sinus/Cosinus itp.) są wykonywane na "kilku" elementach danych.

Z reguły: można założyć, że odczyt/zapis jednego elementu danych z "głównej" pamięci GPU ma opóźnienie około 500 instrukcji....

Dlatego kolejnym kluczowym punktem dla wydajności GPU jest data location : Jeśli musisz odczytywać lub zapisywać dane( a w większości przypadków będziesz musiał; -)), powinieneś upewnić się, że dane są przechowywane jak najbliżej rdzeni GPU. Procesory GPU mają więc pewne obszary pamięci (określane jako "pamięć lokalna" lub "pamięć dzielona"), które zwykle mają tylko kilka KB, ale są szczególnie wydajne dla danych, które mają być zaangażowane w obliczenia.

Aby to jeszcze raz podkreślić: programowanie GPU jest sztuką, która jest tylko zdalnie związana z programowaniem równoległym na CPU. Rzeczy takich jak wątki w Javie, z całą infrastrukturą współbieżności jak ThreadPoolExecutors, ForkJoinPools itd. może sprawić wrażenie że po prostu musisz jakoś podzielić swoją pracę i podzielić ją między kilka procesorów. Na GPU możesz napotkać wyzwania na znacznie niższym poziomie: obłożenie, presja rejestracji, presja pamięci współdzielonej, łączenie pamięci ... żeby wymienić tylko kilka.

Jednak, gdy masz problem związany z równoległymi danymi do rozwiązania, procesor GPU jest dobrym rozwiązaniem.


Ogólna uwaga: twój specjalnie poprosił o CUDA. Ale zdecydowanie polecam również rzucić okiem na OpenCL. Informatyka ma kilka zalet. Po pierwsze, jest to niezależny od dostawców, otwarty standard branżowy, a istnieją implementacje OpenCL firm AMD, Apple, Intel i NVIDIA. Dodatkowo, w świecie Javy istnieje znacznie szersze wsparcie dla OpenCL. Jedynym przypadkiem, w którym wolałbym zadowolić się CUDA, jest użycie bibliotek runtime CUDA, takich jak CUFFT dla FFT lub CUBLAS dla BLAS (operacje macierzowe/wektorowe). Chociaż istnieją podejścia do dostarczania podobnych bibliotek dla OpenCL, nie mogą one być używane bezpośrednio od strony Javy, chyba że tworzysz własne wiązania JNI dla tych bibliotek.


Może być również interesujące usłyszeć, że w październiku 2012 roku grupa OpenJDK HotSpot rozpoczęła projekt "Sumatra": http://openjdk.java.net/projects/sumatra / . Celem tego projektu jest zapewnienie wsparcia GPU bezpośrednio w JVM, z obsługą JIT. Aktualny status i pierwsze wyniki można zobaczyć na ich liście mailingowej pod adresem http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev


[2]} jednak jakiś czas temu zebrałem kilka zasobów związanych z" Java na GPU " w ogóle. Podsumuję je jeszcze raz tutaj, w żadnej konkretnej kolejności.

(Disclaimer : jestem autorem http://jcuda.org / i http://jocl.org/ )

(Bajt)tłumaczenie kodu i generowanie kodu OpenCL:

Https://github.com/aparapi/aparapi : open-source biblioteka tworzona i aktywnie utrzymywana przez firmę AMD. W specjalnej klasie "Kernel" można nadpisać określoną metodę, która powinna być wykonywana równolegle. Kod bajtowy tej metody jest ładowany w czasie wykonywania przy użyciu własnego czytnika kodów bajtowych. Kod jest tłumaczony na kod OpenCL, który jest następnie kompilowany przy użyciu kompilatora OpenCL. Wynik można następnie wykonać na urządzeniu OpenCL, które może być GPU lub CPU. Jeśli kompilacja do OpenCL nie jest możliwa( lub OpenCL nie jest dostępny), Kod nadal będzie wykonywane równolegle, używając puli wątków.

Https://github.com/pcpratts/rootbeer1 : biblioteka open-source do konwersji części Javy do programów CUDA. Oferuje dedykowane interfejsy, które mogą być zaimplementowane w celu wskazania, że pewna klasa powinna być wykonana na GPU. W przeciwieństwie do Aparapi, stara się automatycznie serializować "istotne" dane (czyli kompletną odpowiednią część wykresu obiektowego!) do reprezentacji, która jest odpowiednia dla GPU.

Https://code.google.com/archive/p/java-gpu/: biblioteka do tłumaczenia adnotowanego kodu Javy (z pewnymi ograniczeniami)na kod CUDA, który jest następnie kompilowany do biblioteki, która wykonuje kod na GPU. Biblioteka została opracowana w kontekście pracy doktorskiej, która zawiera dogłębne informacje o procesie tłumaczenia.

Https://github.com/ochafik/ScalaCL : Scala bindings for OpenCL. Pozwala na specjalne kolekcje Scala przetwarzane równolegle z OpenCL. Funkcje, które są wywoływane na elementach zbiorów, mogą być zwykłymi funkcjami Scali (z pewnymi ograniczeniami), które są następnie tłumaczone na jądra OpenCL.

Rozszerzenia językowe

Http://www.ateji.com/px/index.html : rozszerzenie języka Java, które umożliwia równoległe konstrukcje (np. parallel for loops, OpenMP style), które są następnie wykonywane na GPU za pomocą OpenCL. Niestety, ten bardzo obiecujący projekt nie jest już utrzymane.

Http://www.habanero.rice.edu/Publications.html (JCUDA): biblioteka, która może przetłumaczyć specjalny kod Javy (zwany kodem JCUDA) na kod Java - i CUDA-C, który następnie może być skompilowany i wykonany na GPU. Biblioteka nie wydaje się jednak publicznie dostępna.

Https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : rozszerzenie języka Java dla konstrukcji OpenMP, z zapleczem CUDA

Java OpenCL / CUDA binding libraries

Https://github.com/ochafik/JavaCL OpenCL jest biblioteką OpenCL zorientowaną obiektowo, opartą na automatycznie generowanych niskopoziomowych OpenCL.]}

Http://jogamp.org/jocl/www / : wiązania Javy dla OpenCL: obiektowa biblioteka OpenCL, oparta na automatycznie generowanych wiązaniach niskiego poziomu

Http://www.lwjgl.org/: wiązania Javy dla OpenCL: automatycznie generowane wiązania niskiego poziomu i wygoda zorientowana obiektowo klasy

Http://jocl.org/: wiązania Javy dla OpenCL: wiązania niskiego poziomu, które są mapowaniem 1: 1 oryginalnego API OpenCL

Http://jcuda.org/: wiązania Java dla CUDA: wiązania niskiego poziomu, które są mapowaniem 1: 1 oryginalnego API CUDA

Różne

Http://sourceforge.net/projects/jopencl / : wiązania Javy dla OpenCL. Wydaje się, że nie są już utrzymywane od 2010

Http://www.hoopoe-cloud.com / : Wiązania Java dla CUDA. Wydaje się być już nie utrzymywane


 461
Author: Marco13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-10 14:30:14

Zacząłbym od użycia jednego z projektów dla Javy i CUDA: http://www.jcuda.org/

 4
Author: JohnKlehm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-04 16:34:02

Z badań zrobiłem, jeśli celujesz w GPU Nvidia i zdecydowałeś się użyć CUDA nadOpenCL , znalazłem trzy sposoby korzystania z CUDA API w Javie.

  1. JCuda (lub alternatywa)- http://www.jcuda.org / . wydaje się to najlepszym rozwiązaniem problemów, nad którymi pracuję. Wiele bibliotek, takich jak CUBLAS, jest dostępnych w JCuda. Jądra są nadal napisane w języku C.
  2. interfejsy JNI - JNI nie są moimi ulubionymi do pisania, ale są bardzo potężny i pozwoli Ci zrobić wszystko, co CUDA może zrobić.
  3. JavaCPP-to w zasadzie pozwala na tworzenie interfejsu JNI w Javie bez pisania kodu C bezpośrednio. Jest tu przykład: jak najłatwiej uruchomić działający kod CUDA w Javie? o tym, jak używać tego z pchnięciem CUDA. Dla mnie wygląda na to, że równie dobrze możesz napisać interfejs JNI.

Wszystkie te odpowiedzi są w zasadzie tylko sposobami użycia kodu C / C++ w Javie. Powinieneś zadać sobie pytanie, dlaczego trzeba używać Javy, a jeśli nie można tego zrobić w C/C++ zamiast.

Jeśli lubisz Javę i wiesz jak jej używać i nie chcesz pracować z całym zarządzaniem wskaźnikami i co-nie chodzi o c / c++ to JCuda jest prawdopodobnie odpowiedzią. Z drugiej strony, CUDA Thrust library i innych bibliotek, takich jak to może być używany do wielu zarządzania wskaźnikami w C / C++ i może powinieneś na to spojrzeć.

Jeśli lubisz C / C++ i nie przeszkadza Ci zarządzanie wskaźnikami, ale są inne ograniczenia zmuszając cię do używania Javy, JNI może być najlepszym podejściem. Chociaż, jeśli twoje metody JNI będą tylko opakowaniami dla poleceń jądra, równie dobrze możesz użyć JCuda.

Istnieje kilka alternatyw dla JCuda, takich jak Cuda4J i piwo korzenne, ale te nie wydają się być utrzymane. Podczas gdy w momencie pisania tego JCuda obsługuje CUDA 10.1. który jest najbardziej aktualnym SDK CUDA.

Dodatkowo istnieje kilka bibliotek Javy, które używają CUDA, takich jak deeplearning4j i Hadoop, to może być w stanie zrobić to, czego szukasz, bez konieczności pisania kodu jądra bezpośrednio. Nie przyjrzałem się im za bardzo.

 3
Author: David Griffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-02 01:47:59

Marco13 napisał (a):

Jeśli szukasz sposobu na korzystanie z GPU bez implementacji jąder CUDA / OpenCL, chciałbym dodać odniesienie do finmath-lib-cuda-extensions (finmath-lib-gpu-extensions) http://finmath.net/finmath-lib-cuda-extensions / (zastrzeżenie: jestem opiekunem tego projektu).

Projekt zapewnia implementację "klas wektorowych", a dokładniej interfejsu o nazwie RandomVariable, który zapewnia operacje arytmetyczne i redukcję na wektorach. Istnieją implementacje dla CPU i GPU. Istnieją implementacje wykorzystujące różnicowanie algorytmiczne lub zwykłe wyceny.

Poprawa wydajności na GPU jest obecnie niewielka (ale dla wektorów o rozmiarze 100.000 można uzyskać współczynnik > 10 poprawa wydajności). Wynika to z małych rozmiarów jądra. To poprawi się w przyszłej wersji.

Implementacja GPU korzysta z JCuda i JOCL i są dostępne dla GPU Nvidia i ATI.

Biblioteka jest Apache 2.0 i jest dostępna za pośrednictwem Maven Central.

 1
Author: Christian Fries,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-02 01:50:58

Nie ma zbyt wielu informacji na temat natury problemu i danych, więc trudno doradzić. Zaleca jednak ocenę wykonalności innych rozwiązań, które mogą być łatwiejsze do integracji z Javą i umożliwiają skalowanie poziome jak i pionowe. Pierwszy sugerowałbym, aby spojrzeć na to open source analityczny silnik o nazwie Apache Spark https://spark.apache.org/ który jest dostępny na Microsoft Azure, ale prawdopodobnie również na innych dostawców usług IaaS w chmurze. Jeśli trzymasz się jeśli chodzi o procesor graficzny, sugerujemy przyjrzenie się innym bazom analitycznym obsługiwanym przez procesor graficzny dostępnym na rynku, które mieszczą się w budżecie organizacji.

 0
Author: ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-17 22:46:35