В CUDA различные cudaMemcpy*
операции смоделированы после стандартной библиотеки C memcpy
.В этой функции первый указатель всегда указатель назначения, а второй указатель всегда указатель источника.Это также верно для всех cudaMemcpy*
функций.
Поэтому, если вы хотите сделать cudaMemcpyToSymbol
, символ должен быть первым (целевым) аргументом, передаваемым функции (вторым аргументом будетуказатель хоста).Если вы хотите сделать cudaMemcpyFromSymbol
, символ должен быть вторым аргументом (исходной позицией), а указатель хоста является первым аргументом.Это не то, что у вас есть здесь:
cudaError_t err2 = cudaMemcpyFromSymbol(const_d_a, b, size);
^ ^
| This should be the symbol.
|
This is supposed to be the host destination pointer.
Это можно выяснить, просмотрев документацию API .
Если мы изменим порядок этих двух аргументов вэта строка кода:
cudaError_t err2 = cudaMemcpyFromSymbol(b, const_d_a, size);
Ваш код будет работать без ошибок, и напечатанные окончательные результаты будут совпадать.
Нет необходимости использовать амперсанд с любым из a
или b
указатели на эти функции.a
и b
уже указатели.В приведенном вами примере pi_gpu_h
не является указателем.Это обычная переменная.Чтобы скопировать что-то в него, используя cudaMemcpyFromSymbol
, необходимо взять адрес этой обычной переменной, потому что функция ожидает указатель (приемника).
В целом, это выглядит неправильно:
__constant__ float const_d_a[N * sizeof(float)];
Это фактически объявление статического массива, и кроме декоратора __constant__
это должно быть сделано эквивалентно тому, как вы это сделали бы в C или C ++.Нет необходимости умножать N
на sizeof(float)
здесь, если вы хотите сохранить количество N
float
.Просто N
сам сделает это:
__constant__ float const_d_a[N];
, однако, оставив все как есть, не создаст проблем для размещенного вами кода.