CUDA константа памяти

У меня есть массив в постоянной памяти (это глобальная переменная) и получил ссылку на него с помощью вызова функции cudaGetSymbolAddress. Мое ядро ​​работает медленно, когда я использую эту ссылку для извлечения постоянных данных, а не с помощью глобальной переменной. Что является причиной этого?

__constant__ int g[2] = {1,2};
// __device__ int g[2] = {1,2};

// kernel: use by reference
__global__ void add_1( int *a, int *b, int *c, int *f )
{
    int tid = blockIdx.x * blockDim.x + threadIdx.x;
    c[tid] = f[0] * a[tid] + f[1] * b[tid];
}

// kernel: use global variable
__global__ void add_2( int *a, int *b, int *c, int *f )
{
    int tid = blockIdx.x * blockDim.x + threadIdx.x;
    c[tid] = g[0] * a[tid] + f[1] * b[tid];
}

int main()
{
    ......
    // a,b,c are large arrays in device memory of size 40960.

    int *f;
    cudaGetSymbolAddress( (void **)&f, (char *)&g);

    add_1 <<< 160, 256 >>> ( a, b, c, f );

    ......
}

Это пример кода, и все потоки в варпе загружаются в одно и то же место одновременно. Код с комментариями осуществляется путем прямого доступа к постоянной памяти

Объяснение того, почему постоянная кэш-память не используется (talonmies)

Причина в отсутствии постоянного кеша. Кэшированный доступ происходит только тогда, когда компилятор выдает определенную инструкцию PTX (ld.const) для переменной, явно помеченной как находящаяся в пространстве постоянных состояний. И компилятор знает, как это сделать, когда объявлена ​​переменная __constant__ - это статический атрибут времени компиляции, который влияет на генерацию кода. Тот же процесс не может произойти во время выполнения.

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

Неотвеченный вопрос

Почему даже когда массив g объявлен как __device__ переменная, код медленнее, когда ссылка на него используется. Видя PTX код для загрузки глобальной памяти в регистры:

  • 2 инструкции ld.global.s32 используются, который загружает 4 байта в регистр. (в коде с использованием ссылки)
  • 1 инструкция ld.global.v2.s32 используется, который загружает 8 байтов в 2 регистра (в коде с использованием глобальной переменной)

В чем разница, и любая ссылка на документацию будет оценена?

1 ответ

В отличие от глобальной памяти, доступ к постоянной памяти будет сериализован (разделен на несколько транзакций), если они будут неоднородными (все потоки деформации (наполовину для вычислительной возможности 1.x) обращаются к одному и тому же адресу).

Поэтому используйте постоянную память только в том случае, если доступы будут одинаковыми.

Другие вопросы по тегам