Una forma sencilla y rápida de aprender JAVA, observando y deduciendo cómo se comporta el lenguaje a través de ejemplos prácticos.

Archivo del blog

sábado, 6 de agosto de 2016

Uso de la GPU en Java: Producto entre dos arreglos (cublasSdot).

Un ejemplo práctico en el uso de las librerías "JCuda" sería calcular el producto entre dos vectores (arrays), ya que es una operación muy común y podría usarse para calcular totales.

Ejemplo de uso (producto entre dos arrays de datos):

Arrays de datos:
 Precios = {54.1, 21, 8, 39, 12}
 Cantidades = {12, 3, 10, 14, 2}

Cálculos (suma de los productos entre los elementos correspondientes):
 (54.1 * 12) + (21 * 3) + (8 * 10) + (39 * 14) + (12 * 2) = 1362.2

Resultado:
 Total a pagar: 1362.2

*Recordar que antes de empezar hay que agregar al proyecto las librerías jCuda.


Código Java (JavaCudaP1.java):

package javacudap1;

import java.util.Arrays;
import jcuda.Pointer;
import jcuda.Sizeof;
import jcuda.jcublas.JCublas2;
import jcuda.jcublas.cublasHandle;
import static jcuda.jcublas.JCublas2.cublasCreate;
import static jcuda.jcublas.JCublas2.cublasDestroy;
import static jcuda.jcublas.JCublas2.cublasSdot;
import static jcuda.jcublas.JCublas2.cublasSetPointerMode;
import static jcuda.jcublas.cublasPointerMode.CUBLAS_POINTER_MODE_DEVICE;
import jcuda.runtime.JCuda;
import static jcuda.runtime.JCuda.cudaFree;
import static jcuda.runtime.JCuda.cudaMalloc;
import static jcuda.runtime.JCuda.cudaMemcpy;
import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyDeviceToHost;
import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyHostToDevice;

public class JavaCudaP1 {

    public static void main(String[] args) {
        
        // Activa excepciones y omite los errores posteriores:
        JCublas2.setExceptionsEnabled(true);
        JCuda.setExceptionsEnabled(true);

        // Tamaños de los arrays.
        int n = 5;

        // Crea y rellena los datos a tratar (precios y cantidades).
        float hostData1[] = {54.1f, 21f, 8f, 39f, 12f}; // precios
        float hostData2[] = {12f, 3f, 10f, 14f, 2f}; // cantidades

        // Declaración punteros de los datos:
        Pointer deviceData1 = new Pointer();
        Pointer deviceData2 = new Pointer();

        // Reservar espacio en memoria en el dispositivo:
        cudaMalloc(deviceData1, n * Sizeof.FLOAT);
        cudaMalloc(deviceData2, n * Sizeof.FLOAT);

        // Copia las entradas (arrays) al DISPOSITIVO (GPU):
        cudaMemcpy(deviceData1, Pointer.to(hostData1), n * Sizeof.FLOAT, cudaMemcpyHostToDevice);
        cudaMemcpy(deviceData2, Pointer.to(hostData2), n * Sizeof.FLOAT, cudaMemcpyHostToDevice);

        // Crea handle (para el manejo) de las CUBLAS: 
        cublasHandle handle = new cublasHandle();
        cublasCreate(handle);

        // Implica ejecutar el producto de la función dentro el DISPOSITIVO (GPU).
        // El resultado será anotado en un puntero que apunta a la memoria del DISPOSITIVO.
        // Ajusta el modo de puntero a DISPOSITIVO.
        cublasSetPointerMode(handle, CUBLAS_POINTER_MODE_DEVICE);

        // Prepara el puntero para el resultado en la memoria del DISPOSITIVO.
        Pointer deviceResultPointer = new Pointer();
        cudaMalloc(deviceResultPointer, Sizeof.FLOAT);

        // Realiza el calculo producto de los arrays (precios * cantidades).
        cublasSdot(handle, n, deviceData1, 1, deviceData2, 1, deviceResultPointer);

        // Copia el resultado realizado en el DISPOSITIVO (Ram GPU) al Host (Ram CPU).
        float deviceResult[] = {-1f};
        cudaMemcpy(Pointer.to(deviceResult), deviceResultPointer, Sizeof.FLOAT, cudaMemcpyDeviceToHost);

        // Muestra el resultado.
        System.out.println("Precios: \t" + Arrays.toString(hostData1));
        System.out.println("Cantidades: \t" + Arrays.toString(hostData2));
        System.out.println("Total a pagar: \t" + deviceResult[0]);

        // Limpia.
        cudaFree(deviceData1);
        cudaFree(deviceData2);
        cublasDestroy(handle);

    }

}


Resultado:

run:
Precios: [54.1, 21.0, 8.0, 39.0, 12.0]
Cantidades: [12.0, 3.0, 10.0, 14.0, 2.0]
Total a pagar: 1362.2
BUILD SUCCESSFUL (total time: 0 seconds)


Nota: Aunque en el ejemplo los arrays son de solo 5 elementos (n = 5), lo normal sería trabajar con arrays compuestos de millones de elementos, ya que las librerías "jCuda" están pensadas para realizar cálculos masivos.


Con la tecnología de Blogger.