Ошибка CUDA: & quot; динамическая инициализация не поддерживается для переменных __device__, __constant__ и __shared__ & quot;

Я пытаюсь статически инициализировать только для чтения 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 и получить к нему доступ как из кода процессора и графического процессора. Буду признателен, если вы скажете мне, как это сделать правильно.

РЕДАКТИРОВАТЬ:
Мне было указано, что стандартные библиотеки не поддерживаются в коде устройства. Но ошибка, которую я получаю, говорит о том, что это скорее проблема управления памятью.

1

Решение

Инициализация объекта C ++, такого как std::map включает вызов конструктора во время выполнения. Синтаксис C ++ 11, который вы используете для инициализации вашего std::mapс является формой инициализация списка который вызывает std::initializer_list перегрузка std::mapконструктор. Ваш пример с PLAIN_ARRAY не вызывает никаких конструкторов, так как это форма агрегатная инициализация который включает в себя только инициализацию некоторых ints по значению, и инициализация 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`.

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]