Я пытаюсь статически инициализировать только для чтения std::map
Переменные в памяти GPU выглядят следующим образом:
// EXAMPLE 1:
using namespace std;
// first attempt: __device__ extern const
__device__ extern const map<char, const char*> BYTES_TO_WORDS = {
{0xB0, "zero"}, {0xB1, "one"}, {0xB2, "two"}, {0xB3, "three"}};
// second attempt: __const__ static
enum class Color{RED, GREEN, BLUE};
enum class Device{PC, TABLET, PHONE};
__constant__ static map<Color, Device> COLORS_TO_THINGS = {
{Color::RED,Device::PC},{Color::GREEN,Device::TABLET},{Color::BLUE,Device::PHONE}};
Но я получаю следующую ошибку:
dynamic initialization is not supported for __device__, __constant__ and __shared__ variables
Я запутался, потому что я не получаю эту ошибку, когда я пытаюсь что-то вроде этого:
// EXAMPLE 2:
__device__ extern int PLAIN_ARRAY[] = {1, 2, 3, 4, 5};
Я просто хочу иметь возможность создавать и инициализировать только для чтения std::map
и получить к нему доступ как из кода процессора и графического процессора. Буду признателен, если вы скажете мне, как это сделать правильно.
РЕДАКТИРОВАТЬ:
Мне было указано, что стандартные библиотеки не поддерживаются в коде устройства. Но ошибка, которую я получаю, говорит о том, что это скорее проблема управления памятью.
Инициализация объекта C ++, такого как std::map
включает вызов конструктора во время выполнения. Синтаксис C ++ 11, который вы используете для инициализации вашего std::map
с является формой инициализация списка который вызывает std::initializer_list
перегрузка std::map
конструктор. Ваш пример с PLAIN_ARRAY
не вызывает никаких конструкторов, так как это форма агрегатная инициализация который включает в себя только инициализацию некоторых int
s по значению, и инициализация int
не требует вызова конструктора.
В CUDA невозможно использовать любой вид динамической инициализации с глобальными переменными, хранящимися в графическом процессоре, например __device__
а также __constant__
переменные, что означает, что начальное значение объекта должно быть известно во время компиляции, а не только создаваться во время выполнения после вызова конструктора.
Другая проблема заключается в том, что даже в тех случаях, когда вы можете вызывать конструкторы в коде устройства, вы не сможете вызвать конструктор std::map
поскольку, будучи частью стандартной библиотеки C ++, она не имеет __device__
конструктор, и при этом у него нет никаких других __device__
функции-члены, поэтому его можно использовать только из кода хоста. Среда выполнения CUDA не определяет никакой функциональности устройства для классов C ++ STL. Даже если вам удастся cudaMemcpy()
std::map
из памяти хоста в память графического процессора вы не сможете использовать объект, во-первых, потому что все его функции-члены __host__
функции, без __device__
коллеги, а во-вторых, std::map
будет внутренне содержать переменные-указатели, относящиеся к динамически распределяемой памяти хоста, которые не будут действительными адресами памяти в графическом процессоре.
Альтернативой может быть использование простых массивов структур вместо карт, например:
__device__
const struct {
unsigned char byte;
const char word[10];
} BYTES_TO_WORDS[] = {
{0xB0, "zero"},
{0xB1, "one"},
{0xB2, "two"},
{0xB3, "three"}
};
Однако в отличие от std::map
, вам придется реализовать поиск значения по его ключу вручную.
Я просто хочу иметь возможность создавать и инициализировать только для чтения
std::map
а также получить доступ к нему из кода процессора и графического процессора.
К сожалению, это не тривиально, так как вы не можете определить переменную как __device__
а также __host__
, Чтобы получить доступ к __device__
переменная из кода хоста, вам придется использовать cudaMemcpyFromSymbol()
, что довольно неудобно по сравнению с простым доступом к переменной, как обычно. Поэтому вам может потребоваться определить ваши константы в памяти хоста, а затем скопировать ваши константы из памяти хоста в память устройства:
const byte_word BYTES_TO_WORDS[] = {
{0xB0, "zero"},
// ...
};
// uninitialized array
__device__
byte_word DEV_BYTES_TO_WORDS[sizeof BYTES_TO_WORDS / sizeof(byte_word)];
// at startup, use `cudaMemCpyToSymbol()` to populate `DEV_BYTES_TO_WORDS`
// from `BYTES_TO_WORDS`.
Альтернативой может быть использование определения препроцессора для эффективного копирования и вставки одного и того же инициализатора в оба массива, а не копирование данных во время выполнения. В любом случае требуются два отдельных массива.
Других решений пока нет …