CudaMemset не работает с переменной __device__

У меня возникла проблема с использованием cudaMemset в переменной устройства. Можно ли использовать ссылку на переменную устройства для cudaMemset, или это просто вопрос отсутствия флагов компилятора или библиотек. Я использую cuda 4.1 и

версия NVRM: модуль ядра NVIDIA UNIX x86_64 285.05.33 чт 19 января 14:07:02 PST 2012

Это мой пример кода:

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

// device variable and kernel
__device__ float d_test;

int main() {

  if (cudaMemset(&d_test,0,sizeof(float)) !=cudaSuccess)
        printf("Error!\n");
}

который выводит:

Error!

Ответы

Ответ 1

Ваша проблема в том, что d_test (как указано в таблице символов хоста) не является допустимым адресом устройства, и среда выполнения не может получить к ней доступ напрямую. Решение заключается в использовании функции API cudaGetSymbolAddress для чтения адреса символа устройства из контекста во время выполнения. Вот немного расширенная версия вашего демонстрационного примера, которая должна работать правильно:

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

// device variable and kernel
__device__ float d_test;

inline void gpuAssert(cudaError_t code, char * file, int line, bool Abort=true)
{
    if (code != cudaSuccess) {
        fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code),file,line);
        if (Abort) exit(code);
    }       
}

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }

int main()
{

    float * _d_test;

    gpuErrchk( cudaFree(0) );
    gpuErrchk( cudaGetSymbolAddress((void **)&_d_test, "d_test") );
    gpuErrchk( cudaMemset(_d_test,0,sizeof(float)) );

    gpuErrchk( cudaThreadExit() );

    return 0;
}

Здесь мы читаем адрес символа устройства d_test из контекста в указатель узла _d_test. Затем это может быть передано API-интерфейсам хоста, например cudaMemset, cudaMemcpy и т.д.

Ответ 2

Я считаю, что вы также можете использовать cudaMemcpyFromSymbol: Функция, такая как следующее ядро, может изменить значение переменной, объявленной в глобальной памяти (вне основной функции)

__global__ void kernel1() { d_test = 1.0; }

Внутри основного объекта вы можете получить значение с помощью cudaMemcpyFromSymbol

cudaMemcpyFromSymbol(&h_test,"d_test",sizeof(float),0,cudaMemcpyDeviceToHost);

Конечно, есть также cudaMemcpyToSymbol, чтобы изменить значение глобальной переменной.

Идея пришла отсюда: Возникла проблема с назначением переменной устройства в CUDA