Как использовать постоянную память CUDA у программиста приятным способом?
Я работаю над хрустящим приложением, использующим CUDA. У меня есть некоторые статические данные, которые должны быть доступны для всех потоков, поэтому я поместил их в постоянную память следующим образом:
__device__ __constant__ CaseParams deviceCaseParams;
Я использую вызов cudaMemcpyToSymbol для переноса этих параметров с хоста на устройство:
void copyMetaData(CaseParams* caseParams)
{
cudaMemcpyToSymbol("deviceCaseParams", caseParams, sizeof(CaseParams));
}
который работает.
В любом случае, кажется (по пробной версии и ошибкам, а также из чтения сообщений в сети), что по какой-то больной причине объявление deviceCaseParams и его копирование (вызов cudaMemcpyToSymbol) должны быть в одном файле, На данный момент у меня эти два файла .cu, но я действительно хочу иметь структуру параметров в файле .cuh, чтобы любая реализация могла видеть это, если захочет. Это означает, что я также должен иметь функцию copyMetaData в заголовочном файле, но это испортит связывание (уже определенный символ), так как оба файла .cpp и .cu включают этот заголовок (и, таким образом, компилятор MS С++ и nvcc компилирует его).
Есть ли у кого-нибудь советы по дизайну здесь?
Обновление: См. комментарии
Ответы
Ответ 1
С обновленным CUDA (например, 3.2) вы должны иметь возможность делать memcpy из другой единицы перевода, если вы ищете символ во время выполнения (то есть, передавая строку в качестве первого аргумента arg cudaMemcpyToSymbol
, как вы в своем примере).
Кроме того, с помощью устройств класса Fermi вы можете просто разделить память (cudaMalloc
), скопировать в память устройства и передать аргумент как указатель const. Компилятор будет распознавать, если вы равномерно распределяете данные по искажениям, и если так будет использоваться постоянный кеш. Дополнительную информацию см. В Руководстве по программированию CUDA. Примечание: вам нужно скомпилировать с помощью -arch=sm_20
.
Ответ 2
Если вы используете pre-Fermi CUDA, вы обнаружите, что эта проблема относится не только к постоянной памяти, она применима ко всему, что вы хотите на стороне CUDA. Единственные два пути, которые я нашел вокруг этого, - либо:
- Напишите все CUDA в одном файле (.cu) или
- Если вам нужно разбить код на отдельные файлы, ограничьте себя заголовками, которые затем включите ваш единственный файл .cu.
Если вам нужно разделить код между CUDA и C/С++ или иметь общий код, который вы разделяете между проектами, вариант 2 является единственным выбором. С самого начала кажется очень неестественным, но это решает проблему. Вы по-прежнему можете структурировать свой код, просто не в обычном режиме. Главными издержками являются то, что каждый раз, когда вы делаете сборку, вы скомпилируете все. Положительная сторона этого (по-моему, возможно, почему так работает) заключается в том, что компилятор CUDA имеет доступ ко всему исходному коду в одном ударе, который хорош для оптимизации.