Ответ 1
Я могу сказать, что warp должен получить доступ к одному адресу, чтобы получить выгоду от оптимизации/ускорения от постоянного доступа к памяти. Правильно ли это?
Да, это обычно правильно и является основным намерением использовать постоянный кеш памяти/константы. Постоянный кеш может обслуживать одно 32-разрядное количество за цикл для каждого SM. Поэтому, если каждый поток в warp получает одно и то же значение:
int i = array[20];
тогда у вас будет возможность для хорошей выгоды от постоянного кеша/памяти. Если каждый поток в warp получает уникальное количество:
int i = array[threadIdx.x];
тогда доступ будет сериализован, и постоянное использование данных будет неутешительным, с точки зрения производительности.
Я также хочу знать, если я сохраняю структуру вместо простого типа в моей постоянной памяти. Любой доступ к структуре потоком с деформацией; также рассматривается как доступ к одной памяти или более?
Вы можете, конечно, поместить структуры в постоянную память. Те же правила применяются:
int i = constant_struct_ptr->array[20];
имеет возможность воспользоваться, но
int i = constant_struct_ptr->array[threadIdx.x];
нет. Если вы обращаетесь к одному и тому же элементу структуры простой структуры по потокам, это идеально подходит для постоянного использования кеша.
Последний вопрос был бы, если у меня есть массив с постоянными значениями, к которому нужно обращаться через разные потоки в основе; для более быстрого доступа он должен храниться в глобальной памяти вместо постоянной памяти. Это правильно?
Да, если вы знаете, что в целом ваши обращения будут прерывать постоянную память на одно 32-битное количество за цикл, тогда вам, вероятно, будет лучше оставить данные в обычной глобальной памяти.
Существует множество примеров кода cuda, которые демонстрируют использование данных __constant__
. Вот несколько:
- graphics volumeRender
- изображение двустороннего фильтра
- изображение convolutionTexture
- финансирует MonteCarloGPU
и есть другие.
EDIT: отвечает на вопрос в комментариях, если у нас есть такая структура в постоянной памяти:
struct Simple { int a, int b, int c} s;
И мы обращаемся к нему следующим образом:
int p = s.a + s.b + s.c;
^ ^ ^
| | |
cycle: 1 2 3
У нас будет хорошее использование постоянной памяти/кеша. Когда код C скомпилируется, под капотом он будет генерировать коды машинного кода, соответствующие 1,2,3 на диаграмме выше. Представьте себе, что первый доступ происходит первым. Поскольку доступ 1 относится к тому же месту памяти, независимо от того, какой поток в warp, в течение цикла 1, все потоки получат значение в s.a
, и он будет использовать кеш для наилучшей возможной выгоды. Аналогично для доступа 2 и 3. Если, с другой стороны, мы имели:
struct Simple { int a[32], int b[32], int c[32]} s;
...
int idx = threadIdx.x + blockDim.x * blockIdx.x;
int p = s.a[idx] + s.b[idx] + s.c[idx];
Это не даст хорошего использования постоянной памяти/кеша. Вместо этого, если бы это было типично для нашего доступа к s
, мы, вероятно, имели бы лучшую производительность, располагающую s
в обычной глобальной памяти.