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.
de la descripción: El elemento de la magnitud máxima: http://docs.nvidia.com/cuda/cublas/index.html#topic_6_1
if you have { 1, 2, 3, -33, 22, 11 }
resultado será 4! no 5
abs(-33) > 22