programing

Nvidia GPU에서 Java 사용(CUDA)

goodsources 2022. 8. 9. 22:58
반응형

Nvidia GPU에서 Java 사용(CUDA)

저는 Java에서 이루어지는 비즈니스 프로젝트를 진행하고 있는데, 비즈니스 시장을 컴퓨팅하기 위해서는 엄청난 계산 능력이 필요합니다.간단한 수학이지만 엄청난 양의 데이터를 가지고 있습니다.

몇 가지 CUDA GPU를 주문했는데, Java는 CUDA에서 지원되지 않기 때문에 어디서부터 시작할지 고민하고 있습니다.JNI 인터페이스를 구축해야 합니까?JCUDA로 할까요?아니면 다른 방법이 있을까요?

저는 이 분야에 대한 경험이 없기 때문에, 누군가 제가 연구하고 배울 수 있도록 지도해 주셨으면 합니다.

우선 CUDA가 자동으로 연산 속도를 높이는 것은 아니라는 점에 유의해야 합니다.GPU 프로그래밍은 하나의 예술이기 때문에그것을 올바르게 하는 것은 매우 어려운 일이기도 합니다.한편 GPU는 특정 종류의 계산에만 적합하기 때문입니다.

GPU에서는 기본적으로 모든 것을 계산할 수 있기 때문에 혼란스럽게 들릴 수 있습니다.물론 중요한 것은 속도 향상을 제대로 달성할 수 있느냐 여부입니다.여기서 가장 중요한 분류는 문제가 태스크 병렬인지 데이터 병렬인지 여부입니다.첫 번째는 대략적으로 말하면 여러 스레드가 각자의 태스크에서 다소 독립적으로 작동하는 문제를 말합니다.두 번째 문제는 많은 스레드가 모두 동일한 작업을 수행하지만 데이터의 다른 부분에서 발생하는 문제를 말합니다.

후자는 GPU가 잘하는 문제 중 하나입니다.코어 수가 많고 모든 코어가 동일하지만 입력 데이터의 다른 부분에서 작동합니다.

"간단한 수학이지만 방대한 양의 데이터를 가지고 있다"고 말씀하셨습니다.이는 완벽한 데이터 병렬 문제처럼 들리므로 GPU에 적합한 것처럼 들릴 수 있지만, 고려해야 할 또 다른 측면은 GPU가 이론적인 계산 능력(FLOPS, Floating Point Operations Per Second) 면에서 터무니없이 빠르다는 것입니다.그러나 메모리 대역폭에 의해 억제되는 경우가 많습니다.

이것은 또 다른 문제의 분류로 이어집니다.즉, 문제가 메모리 바인딩인지 계산 바인딩인지 여부입니다.

첫 번째 문제는 각 데이터 요소에 대해 수행되는 명령 수가 적은 문제를 말합니다.예를 들어, 다음과 같은 병렬 벡터 덧셈을 고려합니다. 개의 데이터 요소를 읽은 다음 단일 덧셈을 수행한 다음 합계를 결과 벡터에 써야 합니다.GPU에서 이 작업을 수행해도 메모리 읽기/쓰기 작업이 보상되지 않기 때문에 속도가 빨라지지 않습니다.

두 번째 용어인 "compute bound"는 메모리 읽기/쓰기 수에 비해 명령 수가 많은 문제를 의미합니다.예를 들어 행렬 곱셈을 생각해 보겠습니다.명령의 수는 n이 행렬의 크기일 때 O(n^3)가 됩니다.이 경우 GPU가 특정 매트릭스 크기에서 CPU를 능가할 것으로 예상할 수 있습니다.또 다른 예로는 다수의 복잡한 삼각 계산(사인/코사인 등)이 "소량" 데이터 요소에 대해 수행되는 경우를 들 수 있습니다.

경험에 비추어 볼 때:메인 GPU 메모리에서 데이터 요소 하나를 읽고 쓰는 데 약 500개의 명령의 지연이 있다고 가정할 수 있습니다.

따라서 GPU 성능의 또 다른 핵심은 데이터 인접성입니다.데이터를 읽거나 써야 하는 경우(대부분의 경우 ;-), 데이터가 GPU 코어에 가능한 한 가깝게 유지되도록 해야 합니다.따라서 GPU에는 보통 크기가 몇 KB에 불과하지만 계산에 관여하는 데이터에 대해 특히 효율적인 특정 메모리 영역('로컬 메모리' 또는 '공유 메모리'라고 함)이 있습니다.

다시 한 번 강조하자면 GPU 프로그래밍은 CPU의 병렬 프로그래밍과 원격으로만 관련된 기술입니다.Java의 스레드(Treads)와 같은 모든 동시성 인프라스트럭처를 사용하여ThreadPoolExecutors,ForkJoinPools어떤 식으로든 작업을 분할하여 여러 프로세서에 분산해야 한다는 인상을 줄 수 있습니다.GPU에서는, 보다 낮은 레벨의 과제에 직면할 가능성이 있습니다.점유율, 레지스터 압력, 공유 메모리 압력, 메모리 병합...몇 가지 예를 들면요.

그러나 데이터 병렬로 컴퓨팅에 얽매이는 문제를 해결해야 하는 경우에는 GPU를 사용하는 것이 좋습니다.


일반적인 의견: 고객님께서 특별히 CUDA를 요청하셨습니다만, OpenCL도 확인해 보시기 바랍니다.그것은 몇 가지 장점이 있다.먼저 벤더에 의존하지 않는 오픈 업계 표준으로 AMD, Apple, Intel 및 NVIDIA에 의한 OpenCL 구현이 있습니다.또한 Java 세계에서는 OpenCL을 훨씬 더 폭넓게 지원하고 있습니다.CUDA로 만족하는 유일한 경우는 FFT용 CUFFT 또는 BLAS용 CUBLAS(매트릭스/벡터 연산)와 같은 CUBDA 런타임 라이브러리를 사용하는 경우입니다.OpenCL에 유사한 라이브러리를 제공하는 접근법이 있지만 이러한 라이브러리를 위한 JNI 바인딩을 직접 작성하지 않는 한 Java 측에서 직접 사용할 수 없습니다.


또한 2012년 10월에 OpenJDK HotSpot 그룹이 "Sumatra" 프로젝트를 시작했다고 하는 흥미로운 소식도 있을 것입니다.http://openjdk.java.net/projects/sumatra/.이 프로젝트의 목표는 JIT의 지원을 받아 JVM에서 GPU를 직접 지원하는 것입니다.현황과 첫 번째 결과는 메일링 리스트(http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev)에서 확인할 수 있습니다.


다만, 조금 전에, 「GPU상의 자바」에 관한 일반적인 자료를 수집했습니다.여기서 다시 정리하겠습니다.순서는 따로 없습니다.

(면책자:저는 http://jcuda.org/ 및 http://jocl.org/의 저자 입니다.)

(바이트) 코드 변환 및 OpenCL 코드 생성:

https://github.com/aparapi/aparapi : AMD에 의해 작성 및 유지 보수되고 있는 오픈소스 라이브러리.특별한 "Kernel" 클래스에서는 병렬로 실행해야 하는 특정 메서드를 재정의할 수 있습니다.이 메서드의 바이트 코드는 실행 시 자체 바이트 코드 판독기를 사용하여 로드됩니다.코드는 OpenCL 코드로 변환되고 OpenCL 컴파일러를 사용하여 컴파일됩니다.그런 다음 GPU 또는 CPU인 OpenCL 장치에서 실행할 수 있습니다. OpenCL로 컴파일할 수 없는 경우(또는 사용할 수 있는 OpenCL이 없는 경우) 코드는 스레드 풀을 사용하여 병렬로 실행됩니다.

https://github.com/pcpratts/rootbeer1 : Java의 일부를 CUDA 프로그램으로 변환하기 위한 오픈 소스 라이브러리.특정 클래스가 GPU에서 실행되어야 함을 나타내기 위해 구현될 수 있는 전용 인터페이스를 제공합니다.Aparapi와는 달리, 「관련」데이터(즉, 오브젝트 그래프의 완전한 관련 부분!)를 GPU에 적합한 표현으로 자동적으로 시리얼화하려고 합니다.

https://code.google.com/archive/p/java-gpu/ : 주석이 달린 Java 코드를 CUDA 코드로 변환하기 위한 라이브러리입니다.이 라이브러리는 GPU 상에서 코드를 실행하는 라이브러리로 컴파일됩니다.이 라이브러리는 번역 프로세스에 관한 심오한 배경 정보를 포함하는 박사 논문의 맥락에서 개발되었습니다.

https://github.com/ochafik/ScalaCL : Scala bindings for OpenCL. Allows special Scala collections to be processed in parallel with OpenCL. The functions that are called on the elements of the collections can be usual Scala functions (with some limitations) which are then translated into OpenCL kernels.

Language extensions

http://www.ateji.com/px/index.html : A language extension for Java that allows parallel constructs (e.g. parallel for loops, OpenMP style) which are then executed on the GPU with OpenCL. Unfortunately, this very promising project is no longer maintained.

http://www.habanero.rice.edu/Publications.html (JCUDA) : A library that can translate special Java Code (called JCUDA code) into Java- and CUDA-C code, which can then be compiled and executed on the GPU. However, the library does not seem to be publicly available.

https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : Java language extension for for OpenMP constructs, with a CUDA backend

Java OpenCL/CUDA binding libraries

https://github.com/ochafik/JavaCL : Java bindings for OpenCL: An object-oriented OpenCL library, based on auto-generated low-level bindings

http://jogamp.org/jocl/www/ : Java bindings for OpenCL: An object-oriented OpenCL library, based on auto-generated low-level bindings

http://www.lwjgl.org/ : Java bindings for OpenCL: Auto-generated low-level bindings and object-oriented convenience classes

http://jocl.org/ : Java bindings for OpenCL: Low-level bindings that are a 1:1 mapping of the original OpenCL API

http://jcuda.org/ : Java bindings for CUDA: Low-level bindings that are a 1:1 mapping of the original CUDA API

Miscellaneous

http://sourceforge.net/projects/jopencl/ : Java bindings for OpenCL. Seem to be no longer maintained since 2010

http://www.hoopoe-cloud.com/ : Java bindings for CUDA. Seem to be no longer maintained


From the research I have done, if you are targeting Nvidia GPUs and have decided to use CUDA over OpenCL, I found three ways to use the CUDA API in java.

  1. JCuda (or alternative)- http://www.jcuda.org/. This seems like the best solution for the problems I am working on. Many of libraries such as CUBLAS are available in JCuda. Kernels are still written in C though.
  2. JNI - JNI interfaces are not my favorite to write, but are very powerful and would allow you to do anything CUDA can do.
  3. JavaCPP - This basically lets you make a JNI interface in Java without writing C code directly. There is an example here: What is the easiest way to run working CUDA code in Java? of how to use this with CUDA thrust. To me, this seems like you might as well just write a JNI interface.

All of these answers basically are just ways of using C/C++ code in Java. You should ask yourself why you need to use Java and if you can't do it in C/C++ instead.

If you like Java and know how to use it and don't want to work with all the pointer management and what-not that comes with C/C++ then JCuda is probably the answer. On the other hand, the CUDA Thrust library and other libraries like it can be used to do a lot of the pointer management in C/C++ and maybe you should look at that.

If you like C/C++ and don't mind pointer management, but there are other constraints forcing you to use Java, then JNI might be the best approach. Though, if your JNI methods are just going be wrappers for kernel commands you might as well just use JCuda.

There are a few alternatives to JCuda such as Cuda4J and Root Beer, but those do not seem to be maintained. Whereas at the time of writing this JCuda supports CUDA 10.1. which is the most up-to-date CUDA SDK.

Additionally there are a few java libraries that use CUDA, such as deeplearning4j and Hadoop, that may be able to do what you are looking for without requiring you to write kernel code directly. I have not looked into them too much though.

I'd start by using one of the projects out there for Java and CUDA: http://www.jcuda.org/

Marco13 already provided an excellent answer.

In case you are in search for a way to use the GPU without implementing CUDA/OpenCL kernels, I would like to add a reference to the finmath-lib-cuda-extensions (finmath-lib-gpu-extensions) http://finmath.net/finmath-lib-cuda-extensions/ (disclaimer: I am the maintainer of this project).

The project provides an implementation of "vector classes", to be precise, an interface called RandomVariable, which provides arithmetic operations and reduction on vectors. There are implementations for the CPU and GPU. There are implementation using algorithmic differentiation or plain valuations.

The performance improvements on the GPU are currently small (but for vectors of size 100.000 you may get a factor > 10 performance improvements). This is due to the small kernel sizes. This will improve in a future version.

The GPU implementation use JCuda and JOCL and are available for Nvidia and ATI GPUs.

The library is Apache 2.0 and available via Maven Central.

There is not much information on the nature of the problem and the data, so difficult to advise. However, would recommend to assess the feasibility of other solutions, that can be easier to integrate with java and enables horizontal as well as vertical scaling. The first I would suggest to look at is an open source analytical engine called Apache Spark https://spark.apache.org/ that is available on Microsoft Azure but probably on other cloud IaaS providers too. If you stick to involving your GPU then the suggestion is to look at other GPU supported analytical databases on the market that fits in the budget of your organisation.

ReferenceURL : https://stackoverflow.com/questions/22866901/using-java-with-nvidia-gpus-cuda

반응형