Прежде чем мы углубимся в кодирование некоторого фона. Существует два конкурирующих пакета GPGPU: OpenCL и CUDA . OpenCL — это открытый стандарт, поддерживаемый всеми поставщиками графических процессоров (а именно AMD, NVIDIA и Intel), в то время как CUDA относится к NVIDIA и будет работать только на картах NVIDIA. Оба SDK поддерживают код C / C ++, что, конечно же, оставляет нас Java-разработчиками на холоде. До сих пор нет чистой поддержки OpenCL или CUDA в Java. Это не сильно поможет программисту на Java, которому нужно использовать огромный потенциал параллелизма графического процессора, если она не возится с интерфейсом Java Native. Конечно, есть некоторые инструменты Java, которые облегчают боль программирования Java GPGPU.
Два самых популярных (IMHO) — это jocl и jcuda . С этими инструментами вам все равно придется писать код на C / C ++, но, по крайней мере, это будет только для кода, который будет выполняться в GPU, что значительно минимизирует усилия.
На этот раз я посмотрю на jcuda и посмотрю, как мы можем написать простую программу GPGPU.
Давайте начнем с настройки среды разработки Linux CUDA GPGPU (хотя среды Windows и Mac также не должны быть сложными в настройке):
Шаг 1 : Установите графический процессор с поддержкой NVIDIA CUDA на свой компьютер. На сайте разработчиков NVIDIA есть список графических процессоров с поддержкой CUDA. Новые графические процессоры NVIDIA почти наверняка поддерживают CUDA, но на всякий случай проверьте спецификацию карты, чтобы убедиться…
Шаг 2 : Установите драйвер NVIDIA и CUDA SDK. Скачайте их и найдите инструкции по установке здесь .
Шаг 3 : Перейдите в каталог ~ / NVIDIA_GPU_Computing_SDK / C / src / deviceQuery и запустите make .
Шаг 4 : Если компиляция прошла успешно, перейдите в каталог ~ / NVIDIA_GPU_Computing_SDK / C / bin / linux / release и запустите файл deviceQuery . Вы получите много технической информации о вашей карте.
Вот что я получил для своей карты GeForce GT 430:
Обратите внимание на 2 мультипроцессора с 48 ядрами CUDA на 96 ядер, что неплохо для недорогой видеокарты стоимостью около 40 евро !!!!
Шаг 5 : Теперь, когда у вас есть среда CUDA, давайте напишем и скомпилируем программу CUDA на C. Напишите следующий код и сохраните его как multiply.cu
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >#include <iostream></span> #include <iostream></span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >__global__ void multiply( float a, float b, float * c)</span> __global__ void multiply (плавать a, плавать b, плавать * c)</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >{</span> {</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >*c=a*b;</span> * С = а * Ь;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >}</span> }</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > int main()</span> int main ()</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >{</span> {</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > float a, b, c;</span> плавать а, б, в;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > float *c_pointer;</span> float * c_pointer;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >a=1.35;</span> а = 1,35;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >b=2.5;</span> б = 2,5;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cudaMalloc(( void **)&c_pointer, sizeof ( float ));</span> cudaMalloc (( void **) & c_pointer, sizeof ( float ));</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >multiply<<<1,1>>>(a, b, c_pointer);</span> умножить <<< 1,1 >>> (a, b, c_pointer);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cudaMemcpy(&c, c_pointer, sizeof ( float ),cudaMemcpyDeviceToHost);</span> cudaMemcpy (& c, c_pointer, sizeof ( float ), cudaMemcpyDeviceToHost);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > /*** This is C!!!</span> / *** Это С !!!</span> <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">You manage your garbage on your own!</span> Вы сами управляете мусором!</span> <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">***/ </span> *** /</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cudaFree(c_pointer);</span> cudaFree (c_pointer);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > printf ( "Result = %f\n" ,c);</span> printf ( "Результат =% f \ n" , c);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >}</span> }</span> |
Скомпилируйте его с помощью компилятора cuda и запустите:
1
2
3
4
|
<span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$ nvcc multiply.cu -o multiply< /span > $ nvcc multiply.cu -o multiply< /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$ . /multiply < /span > $ . /multiply < /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >Result = 3.375000< /span > Результат = 3.375000< /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$< /span > $< /span > |
Итак, что делает приведенный выше код? Функция умножения с квалификатором __global__ называется ядром и представляет собой фактический код, который будет выполняться в графическом процессоре. Код в главной функции выполняется в CPU как обычный код на C, хотя есть некоторые семантические различия:
- Функция умножения вызывается в скобках <<< 1,1 >>>. Два числа в скобках указывают CUDA, сколько раз код должен быть выполнен. CUDA позволяет нам создавать так называемые одно-, двух- или даже трехмерные потоковые блоки. Числа в этом примере указывают на один блок потока, работающий в одном измерении, таким образом, наш код будет выполнен 1 × 1 = 1 раз.
- Функции cudaMalloc, cudaMemcpy и cudaFree используются для обработки памяти графического процессора аналогично тому, как мы обрабатываем обычную память компьютера в C. Функция cudaMemcpy важна, поскольку у GPU есть собственная RAM, и прежде чем мы сможем обрабатывать любые данные в ядре нам нужно загрузить их в память GPU. Конечно, мы также должны скопировать результаты обратно в обычную память, когда закончите.
Теперь, когда мы получили основы того, как выполнять код в графическом процессоре, давайте посмотрим, как мы можем запускать код GPGPU из Java. Помните, что код ядра по-прежнему будет написан на C, но по крайней мере основной функцией теперь является java-код с помощью jcuda.
Загрузите двоичные файлы jcuda, разархивируйте их и убедитесь, что каталог, содержащий файлы .so (или .dll для Windows), указан либо в параметре java.library.path JVM, либо добавлен в переменную среды LD_LIBRARY_PATH (или ваша переменная PATH в windows). Точно так же файл jcuda-xxxxxxx.jar должен находиться в вашем classpath во время компиляции и выполнения вашей Java-программы.
Итак, теперь, когда у нас есть настройка jcuda, давайте посмотрим на наше jcuda-совместимое ядро:
1
2
3
4
5
6
|
<span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > extern "C" </span> внешний "C" </span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >__global__ void multiply( float *a, float *b, float *c)</span> __global__ void multiply ( float * a, float * b, float * c)</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > /*************** Kernel Code **************/ </span> / *************** Код ядра ************** /</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >{</span> {</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >c[0]= a[0] * b[0];</span> c [0] = a [0] * b [0];</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >}</span> }</span> |
Вы заметите следующие отличия от предыдущего метода ядра:
- Мы используем квалификатор extern «C», чтобы сказать компилятору не смешивать имя метода умножения, чтобы мы могли вызывать его с его исходным именем.
- Мы используем массивы вместо примитивов для a, b и c. Это требуется jcuda, поскольку примитивы Java не поддерживаются jcuda. В jcuda данные передаются назад и вперед в GPU в виде массивов, таких как числа с плавающей запятой, целые числа и т. Д.
Сохраните этот файл как multiply2.cu . На этот раз мы не хотим компилировать файл как исполняемый файл, а скорее как библиотеку CUDA, которая будет вызываться в нашей java-программе. Мы можем скомпилировать наше ядро в виде файла PTX или файла CUBIN. PTX — это удобочитаемые файлы, содержащие код, подобный сборке, который будет скомпилирован на лету. Файлы CUBIN являются скомпилированными CUda BINaries и могут вызываться напрямую, без компиляции на лету. Если вам не нужна оптимальная производительность при запуске, файлы PTX предпочтительнее, поскольку они не привязаны к конкретной вычислительной способности графического процессора, с которым они были скомпилированы, в то время как файлы CUBIN не будут работать на графических процессорах с меньшей вычислительной способностью.
Чтобы скомпилировать наше ядро, наберите следующее:
1
|
<span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$ nvcc -ptx multiply2.cu -o multiply2.ptx< /span > $ nvcc -ptx multiply2.cu -o multiply2.ptx< /span > |
Успешно создав наш файл PTX, давайте посмотрим на Java-эквивалент основного метода, который мы использовали в нашем примере C:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
<span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > import static jcuda.driver.JCudaDriver.*;</span> импортировать статический jcuda.driver.JCudaDriver. *;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > import jcuda.*;</span> импорт jcuda. *;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > import jcuda.driver.*;</span> импорт jcuda.driver. *;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > import jcuda.runtime.JCuda;</span> import jcuda.runtime.JCuda;</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > public class MultiplyJ {</span> открытый класс MultiplyJ {</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > public static void main(String[] args) {</span> public static void main (String [] args) {</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > float [] a = new float [] {( float ) 1.35 };</span> float [] a = new float [] {( float ) 1.35 };</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > float [] b = new float [] {( float ) 2.5 };</span> float [] b = new float [] {( float ) 2.5 };</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" > float [] c = new float [ 1 ];</span> float [] c = новый float [ 1 ];</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuInit( 0 );</span> cuInit ( 0 );</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUcontext pctx = new CUcontext();</span> CUcontext pctx = новый CUcontext ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUdevice dev = new CUdevice();</span> CUdevice dev = new CUdevice ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuDeviceGet(dev, 0 );</span> cuDeviceGet (dev, 0 );</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuCtxCreate(pctx, 0 , dev);</span> cuCtxCreate (pctx, 0 , dev);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUmodule module = new CUmodule();</span> Модуль CUmodule = новый CUmodule ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuModuleLoad(module, "multiply2.ptx" );</span> cuModuleLoad (модуль, «multiply2.ptx»);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUfunction function = new CUfunction();</span> Функция CUfunction = новая функция CUfunction ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuModuleGetFunction(function, module, "multiply" );</span> cuModuleGetFunction (функция, модуль, «умножение»);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUdeviceptr a_dev = new CUdeviceptr();</span> CUdeviceptr a_dev = new CUdeviceptr ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuMemAlloc(a_dev, Sizeof.FLOAT);</span> cuMemAlloc (a_dev, Sizeof.FLOAT);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuMemcpyHtoD(a_dev, Pointer.to(a), Sizeof.FLOAT);</span> cuMemcpyHtoD (a_dev, Pointer.to (a), Sizeof.FLOAT);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUdeviceptr b_dev = new CUdeviceptr();</span> CUdeviceptr b_dev = new CUdeviceptr ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuMemAlloc(b_dev, Sizeof.FLOAT);</span> cuMemAlloc (b_dev, Sizeof.FLOAT);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuMemcpyHtoD(b_dev, Pointer.to(b), Sizeof.FLOAT);</span> cuMemcpyHtoD (b_dev, Pointer.to (b), Sizeof.FLOAT);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >CUdeviceptr c_dev = new CUdeviceptr();</span> CUdeviceptr c_dev = new CUdeviceptr ();</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuMemAlloc(c_dev, Sizeof.FLOAT);</span> cuMemAlloc (c_dev, Sizeof.FLOAT);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >Pointer kernelParameters = Pointer.to(</span> Pointer kernelParameters = Pointer.to (</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >Pointer.to(a_dev),</span> Pointer.to (a_dev),</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >Pointer.to(b_dev),</span> Pointer.to (b_dev),</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >Pointer.to(c_dev)</span> Pointer.to (c_dev)</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >);</span> );</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuLaunchKernel(function, 1 , 1 , 1 , 1 , 1 , 1 , 0 , null , kernelParameters, null );</span> cuLaunchKernel (function, 1 , 1 , 1 , 1 , 1 , 1 , 0 , null , kernelParameters, null );</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >cuMemcpyDtoH(Pointer.to(c), c_dev, Sizeof.FLOAT);</span> cuMemcpyDtoH (Pointer.to (c), c_dev, Sizeof.FLOAT);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >JCuda.cudaFree(a_dev);</span> JCuda.cudaFree (a_dev);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >JCuda.cudaFree(b_dev);</span> JCuda.cudaFree (b_dev);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >JCuda.cudaFree(c_dev);</span> JCuda.cudaFree (c_dev);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >System.out.println( "Result = " +c[ 0 ]);</span> System.out.println ( "Result =" + c [ 0 ]);</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >}</span> }</span> <span class = "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class = "google-src-text" style= "direction: ltr; text-align: left" >}</span> }</span> |
Хорошо, это похоже на большой код для простого умножения двух чисел, но помните, что существуют ограничения относительно указателей Java и C. Итак, начиная со строк с 9 по 11, мы преобразуем наши параметры a, b и c в массивы с именами a, b и c, каждый из которых содержит только одно число с плавающей точкой.
В строках с 13 по 17 мы сообщаем jcuda, что будем использовать первый графический процессор в нашей системе (в высокопроизводительных системах можно использовать более одного графического процессора).
В строках с 19 по 22 мы сообщаем jcuda, где находится наш PTX-файл, и имя метода ядра, который мы хотели бы использовать (в нашем случае умножение .)
Вещи становятся интересными в строке 24, где мы используем специальный класс jcuda CUdeviceptr, который действует как заполнитель указателя. В строке 25 мы используем указатель CUdeviceptr, который мы только что создали для выделения памяти GPU. Обратите внимание, что если бы в нашем массиве было более одного элемента, нам нужно было бы умножить константу Sizeof.FLOAT на количество элементов в нашем массиве. Наконец, в строке 26 мы копируем содержимое нашего первого массива в графический процессор. Точно так же мы создаем наш указатель и копируем содержимое в ОЗУ графического процессора для нашего второго массива (b). Для нашего выходного массива (c) нам нужно только выделить память GPU.
В строке 35 мы создаем объект Pointer, который будет содержать все параметры, которые мы хотим передать нашему методу умножения .
Мы выполняем наш код ядра в строке 41, где мы выполняем служебный метод cuKernelLaunch, передавая классы функций и указателей в качестве параметров. Первые шесть параметров после параметра функции определяют количество сеток (сетка — это группа блоков) и блоков, которые в нашем примере равны 1, так как мы будем выполнять ядро только один раз. Следующие два параметра — 0 и ноль и используются для идентификации любой разделяемой памяти (памяти, которая может быть разделена между потоками), которую мы, возможно, определили, в нашем случае ни одного. Следующий параметр содержит созданный нами объект Pointer, содержащий указатели на устройства a, b, c, а последний параметр предназначен для дополнительных опций.
После возвращения нашего ядра мы просто копируем содержимое dev_c в наш массив c, освобождаем всю память, выделенную в GPU, и печатаем результат, сохраненный в c [0], что, конечно, так же, как в нашем примере на C.
Вот как мы компилируем и выполняем программу MultiplyJ.java (при условии, что multiply2.ptx находится в том же каталоге):
1
2
3
4
5
|
<span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$ javac - cp ~ /GPGPU/jcuda/JCuda-All-0 .4.0-beta1-bin-linux-x86_64 /jcuda-0 .4.0-beta1.jar MultiplyJ.java< /span > $ javac - cp ~ / GPGPU / jcuda / JCuda-All-0.4.0-beta1-bin-linux-x86_64 / jcuda-0.4.0-beta1.jar MultiplyJ.java< /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$ java - cp ~ /GPGPU/jcuda/JCuda-All-0 .4.0-beta1-bin-linux-x86_64 /jcuda-0 .4.0-beta1.jar:.< /span > $ java - cp ~ / GPGPU / jcuda / JCuda-All-0.4.0-beta1-bin-linux-x86_64 / jcuda-0.4.0-beta1.jar :.< /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >MultiplyJ< /span > MultiplyJ< /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >Result = 3.375< /span > Результат = 3,375< /span > <span class= "notranslate" onmouseover= "_tipon(this)" onmouseout= "_tipoff()" ><span class= "google-src-text" style= "direction: ltr; text-align: left" >$< /span > $< /span > |
Обратите внимание, что в этом примере каталог ~ / GPGPU / jcuda / JCuda-All-0.4.0-beta1-bin-linux-x86_64 уже находится в моем LD_LIBRARY_PATH, поэтому мне не нужно устанавливать параметр java.library.path в JVM.
Надеюсь, к настоящему моменту механика jcuda ясна, хотя мы на самом деле не затрагивали истинную силу GPU — массовый параллелизм. В следующей статье я приведу пример того, как запускать параллельные потоки в CUDA с использованием Java, а также пример того, что НЕ нужно запускать в графическом процессоре. Обработка на GPU имеет смысл для очень специализированных задач, и большинство задач лучше оставить для обработки нашим старым и доверенным процессором.
Справка: GPGPU Java Programming от нашего партнера W4G Спироса Сакеллариу .
Статьи по Теме :