Ошибка основных операций CUDA - PullRequest
0 голосов
/ 29 октября 2011

У меня есть глобальная функция следующим образом:

__global__ void sort(float* D,  float* new_D)
{
        int  i  = threadIdx.x + blockIdx.x * blockDim.x ;   // i>=0 && i<N

        new_D[ 4*(i/4)+i%2]   = D[ 4*(i/4)+2*(i%2) ];
}

И она называется так:

sort <<< (N / threadperblock), threadperblock >>> (D, new_D);

Функция работает неправильно, когда я определяю «N» более 2048 с одинарной точностью и 4096 с двойной точностью, поскольку я получаю неправильные ответы.Что не так?

Ответы [ 2 ]

1 голос
/ 30 октября 2011

Абсолютно невозможно сказать что-либо о том, почему вы не получаете ожидаемых результатов из своего кода.Очевидным источником ошибки была бы неинициализированная память.Ваша схема индексации присваивает значения только половине new_D, поэтому, если вы не предприняли преднамеренных шагов для присвоения значений другим значениям, тогда результаты будут содержать неинициализированные значения и несоответствия или неожиданные значения между версией графического процессора и реализацией хоста.может произойти.

Чтобы проиллюстрировать мою точку зрения, вот полный случай воспроизведения, который корректно работает при любом входном размере, который является степенью двойки:

#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

const int N = (2<<20);

__global__ void sort(float* D,  float* new_D)
{
    int  i  = threadIdx.x + blockIdx.x * blockDim.x ;   // i>=0 && i<N
    new_D[ 4*(i/4)+i%2]   = D[ 4*(i/4)+2*(i%2) ];
}

__host__ void host_sort(const float* D,  float* new_D)
{
    for(int i=0; i<N; i++)
        new_D[ 4*(i/4)+i%2]   = D[ 4*(i/4)+2*(i%2) ];
}

int main(void)
{

    const size_t dsize =sizeof(float) * size_t(N);

    float *D = (float *)malloc(dsize);  
    float *new_D = (float *)malloc(dsize);  
    for(int i=0; i<N; i++) {
        D[i] = (float)i;
        new_D[i] = -999.0f;
    }

    float *D_gpu, *new_D_gpu;
    assert( cudaMalloc((void**)&D_gpu, dsize) == cudaSuccess );
    assert( cudaMemcpy(D_gpu, D, dsize, cudaMemcpyHostToDevice) == cudaSuccess); 
    assert( cudaMalloc((void**)&new_D_gpu, dsize) == cudaSuccess );
    assert( cudaMemcpy(new_D_gpu, new_D, dsize, cudaMemcpyHostToDevice) == cudaSuccess); 
    dim3 blocksize = dim3(128,1,1);
    dim3 gridsize = dim3(N/blocksize.x,1,1);

    host_sort(D, new_D);

    sort<<< gridsize, blocksize >>>(D_gpu,new_D_gpu);
    assert( cudaPeekAtLastError() == cudaSuccess );
    assert( cudaThreadSynchronize() == cudaSuccess );

    float *new_D_host = (float *)malloc(dsize); 
    assert( cudaMemcpy(new_D_host, new_D_gpu, dsize, cudaMemcpyDeviceToHost) == cudaSuccess); 

    for(int i=0; i<N; i++) 
        assert( new_D_host[i] == new_D[i] );

    return 0;
}

Вы должны знать, что половинапотоки в вашем ядре эффективно выполняют избыточные назначения и, как следствие, излишне записывают пропускную способность памяти.

0 голосов
/ 30 октября 2011

Что такое значение threadperblock? Изменится ли он, когда вы работаете с одинарной или двойной прецизионностью?

Причина, по которой я спрашиваю --- threadIdx.x, blockIdx.x и blockDim.x работают как unsigned short. Максимальное значение, которое они могут содержать, составляет 65535, пока вы не приведете его к int. Если вы превысите это значение, в том числе и при выполнении математических операций, вы можете получить действительно странные результаты.

Попробуйте это:

int i=blockDim.x;
i=i*blockIdx.x+threadIdx.x
...