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.

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.


1 comentario:

  1. como seria el algoritmo si tuviese que hacerlo con double? ya probé cambiando el tipo de variable.. pero no da los resultados que corresponden, Saludos!

    ResponderEliminar

Con la tecnología de Blogger.