c++ c cuda cublas

c++ - Encontrar el máximo y mínimo con CUBLAS



cuda (2)

Tengo problemas para comprender por qué mi función que encuentra el máximo y mínimo en un rango de dobles con CUBLAS no funciona correctamente.

El código es el siguiente:

void findMaxAndMinGPU(double* values, int* max_idx, int* min_idx, int n) { double* d_values; cublasHandle_t handle; cublasStatus_t stat; safecall( cudaMalloc((void**) &d_values, sizeof(double) * n), "cudaMalloc (d_values) in findMaxAndMinGPU"); safecall( cudaMemcpy(d_values, values, sizeof(double) * n, cudaMemcpyHostToDevice), "cudaMemcpy (h_values > d_values) in findMaxAndMinGPU"); cublasCreate(&handle); stat = cublasIdamax(handle, n, d_values, sizeof(double), max_idx); if (stat != CUBLAS_STATUS_SUCCESS) printf("Max failed/n"); stat = cublasIdamin(handle, n, d_values, sizeof(double), min_idx); if (stat != CUBLAS_STATUS_SUCCESS) printf("min failed/n"); cudaFree(d_values); cublasDestroy(handle); }

Donde valores son los valores para buscar dentro. Max_idx y min_idx son el índice de los números encontrados en los valores. Los resultados de las llamadas CUBLAS parecen bastante aleatorios y arrojan índices incorrectos.

¿Alguien con una gran respuesta a mi problema? Estoy un poco triste en este momento :(


Uno de sus argumentos para las llamadas cublasIdamax y cublasIdamin es incorrecto. El argumento incx en BLAS llamadas de nivel 1 siempre debe ser el paso de la entrada en palabras, no en bytes. Entonces sospecho que quieres algo más como:

stat = cublasIdamax(handle, n, d_values, 1, max_idx); if (stat != CUBLAS_STATUS_SUCCESS) printf("Max failed/n"); stat = cublasIdamin(handle, n, d_values, 1, min_idx); if (stat != CUBLAS_STATUS_SUCCESS) printf("min failed/n");

Al usar sizeof(double) le está diciendo a las rutinas que utilicen una zancada de 8, lo que hará que las llamadas rebasen el almacenamiento asignado de la matriz de entrada y la memoria no inicializada. Supongo que realmente tiene un paso de 1 en d_values .

Editar: Aquí hay un ejemplo ejecutable completo que funciona correctamente. Tenga en cuenta que cambié el código a una sola precisión porque actualmente no tengo acceso a hardware capaz de doble precisión:

#include <cuda_runtime.h> #include <cublas_v2.h> #include <cstdio> #include <cstdlib> #include <sys/time.h> typedef float Real; void findMaxAndMinGPU(Real* values, int* max_idx, int* min_idx, int n) { Real* d_values; cublasHandle_t handle; cublasStatus_t stat; cudaMalloc((void**) &d_values, sizeof(Real) * n); cudaMemcpy(d_values, values, sizeof(Real) * n, cudaMemcpyHostToDevice); cublasCreate(&handle); stat = cublasIsamax(handle, n, d_values, 1, max_idx); if (stat != CUBLAS_STATUS_SUCCESS) printf("Max failed/n"); stat = cublasIsamin(handle, n, d_values, 1, min_idx); if (stat != CUBLAS_STATUS_SUCCESS) printf("min failed/n"); cudaFree(d_values); cublasDestroy(handle); } int main(void) { const int vmax=1000, nvals=10000; float vals[nvals]; srand ( time(NULL) ); for(int j=0; j<nvals; j++) { vals[j] = float(rand() % vmax); } int minIdx, maxIdx; findMaxAndMinGPU(vals, &maxIdx, &minIdx, nvals); int cmin = 0, cmax=0; for(int i=1; i<nvals; i++) { cmin = (vals[i] < vals[cmin]) ? i : cmin; cmax = (vals[i] > vals[cmax]) ? i : cmax; } fprintf(stdout, "%d %d %d %d/n", minIdx, cmin, maxIdx, cmax); return 0; }

que cuando se compila y ejecuta da esto:

$ g++ -I/usr/local/cuda/include -L/usr/local/cuda/lib cublastest.cc -lcudart -lcublas $ ./a.out 273 272 85 84

tenga en cuenta que CUBLAS sigue la convención FORTRAN y usa 1 indexación, en lugar de indexación cero, por lo que hay una diferencia de 1 entre las versiones CUBLAS y CPU.