2012-09-25 3 views
4

Итак, идея о том, что у меня есть совместные обращения к памяти в CUDA, заключается в том, что потоки в warp должны обращаться к смежным адресам памяти, поскольку это приведет только к транзакции с одной памятью (значения для каждого адрес затем передаются в потоки) вместо нескольких, которые будут выполняться последовательным образом.CUDA - Коалесцирующие доступ к памяти и ширина шины

Теперь ширина моей шины составляет 48 байт. Это означает, что я могу передать 48 байтов на каждую транзакцию памяти, правильно? Таким образом, чтобы полностью использовать преимущества шины, я должен был бы иметь возможность читать 48 байтов за раз (путем чтения более одного байта на транзакции с потоком - память выполняется warp). Однако гипотетически не будет иметь ни одного потока, читающего 48 байтов за один раз, чтобы обеспечить такое же преимущество (я предполагаю, что могу читать 48 байтов за раз, читая структуру размером 48 байт)?

Моя проблема с коалесценцией - это перенос, который я должен делать с данными. У меня много данных, поэтому для переноса это требует времени, которое я предпочел бы использовать для чего-то еще, если бы мог.

Я нахожусь на Compute Capability 2.0.

ответ

7

Шина памяти вашего GPU не просто ширина 48 байтов (что было бы довольно громоздким, так как это не сила 2). Вместо этого он состоит из 6 каналов памяти по 8 байтов (по 64 бита). Операции с памятью обычно намного шире, чем ширина канала, чтобы использовать режим пакетной памяти. Хорошие размеры транзакций начинаются с 64 байтов, чтобы создать пакет размером 8, который хорошо сочетается с 16 32-битными словами полувращения на вычислительных возможностях 1.x.

128-байтовые транзакции по-прежнему немного быстрее и соответствуют 32-разрядным доступам на основе ширины основы для устройств с возможностью вычисления 2.0 (и выше). Кэш-линии также имеют ширину 128 байтов. Обратите внимание, что все эти обращения должны быть выровнены по кратности ширины транзакции, чтобы сопоставить одну транзакцию с памятью.

Теперь о вашей реальной проблеме, , лучше всего ничего не делать и позволить кешу сортировать его. Это работает так же, как вы явно делаете в общей памяти, просто для того, чтобы это было сделано с помощью аппаратного обеспечения кеша, и для него не нужен код, что должно сделать его немного быстрее. Единственное, о чем нужно беспокоиться, - иметь достаточное количество кеш-памяти, чтобы каждый warp мог иметь необходимые 32 × 32 × 4 байта = 4 Кбайт кэша для ширины слова (например, float) или 8 кбайт для двойного доступа.Это означает, что может быть полезно ограничить количество перекосов, которые одновременно активны, чтобы предотвратить их перекоса строк кэша друг друга.

Для специальных оптимизаций существует также возможность использования векторных типов, таких как float2 или float4, так как все графические процессоры, поддерживающие CUDA, имеют инструкции по загрузке и хранению, которые отображают 8 или 16 байтов в один поток. Однако при вычислительной способности 2.0 и выше я действительно не вижу никакого преимущества использования их в общем случае транспозиции матрицы, поскольку они еще больше увеличивают размер кэша каждой основы.

Поскольку значение по умолчанию для общей кэш-памяти 16 КБ/48 КБ позволяет использовать четыре перекоса на каждый SM для выполнения транспонирования в любой момент времени (при отсутствии другого доступа к памяти одновременно), вероятно, полезно выбрать настройка общей памяти 48 кБ/16 КБ по умолчанию по умолчанию 16 кБ/48 кБ с использованием cudaDeviceSetCacheConfig().

Для полноты я также упомянул, что инструкции shuffle warp, представленные с возможностью вычисления 3.0, позволяют обмениваться данными регистров в пределах основы без прохождения через кэш или через общую память. Подробнее см. В разделе Appendix B.14 руководства по программированию CUDA C.
(Обратите внимание, что версия руководства по программированию существует без этого приложения. Поэтому, если в вашей копии Приложение B.13 есть что-то еще, перезагрузите его через предоставленную ссылку).

6

В целях коалесцирования, как вы заявили, вы должны сосредоточиться на том, чтобы 32 потока в непрерывном доступе к основанию, предпочтительно 32-байтовые или 128-байтовые выровненные. Помимо этого, не беспокойтесь о физической адресной шине в памяти DRAM. Контроллер памяти состоит из в основном независимых разделов, каждый из которых имеет ширину 64 бит. Ваш объединенный доступ, выходящий из основы, будет выполняться как можно быстрее контроллером памяти. Единый объединенный доступ для полного warp (32 потока), получающий доступ к int или float, потребует 128 байтов, которые будут извлечены в любом случае, то есть несколько транзакций на физической шине в DRAM. Когда вы работаете в режиме кэширования, вы не можете контролировать гранулярность запросов в глобальной памяти ниже 128 байт за раз.

Невозможно заставить один поток запросить 48 байтов или что-либо подобное в одной транзакции. Даже на уровне кода c, если вы считаете, что сразу получаете доступ к целой структуре данных, на уровне машинного кода он преобразуется в инструкции, которые читают 32 или 64 бита за раз.

Если вы считаете, что ограничение на кеширование по 128 байт за раз, это наказание вашего кода, вы можете попробовать работать в режиме без кэша, что уменьшит степень детализации запросов глобальной памяти до 32 байтов за раз. Если у вас есть разбросанная схема доступа (недостаточно хорошо объединенная), этот параметр может дать лучшую производительность.

Смежные вопросы