Я считаю, что существует фундаментальное недопонимание того, что такое союз.
Давайте подумаем об этом. Что отличает объединение от структуры? Он может хранить разные типы данных в разное время.
Как он совершает этот подвиг? Хорошо, можно использовать какую-то отдельную переменную для динамического определения типа или объема памяти, который он занимает, но Union этого не делает, он полагается на то, что программист точно знает, какой тип они хотят получить и когда. Таким образом, единственная альтернатива, если тип фактически известен только программисту в любой данный момент времени, это просто убедиться, что для вашей переменной union достаточно места, чтобы можно было всегда использовать его для любого типа.
Действительно, это то, что делает объединение, см. здесь (да, я знаю, что это C / C ++, но это также относится и к CUDA). Что это значит для вас? Это означает, что размер вашего массива объединения должен соответствовать размеру его наибольшего члена x числу элементов, поскольку размер объединения равен размеру его наибольшего члена.
Давайте посмотрим на ваш союз, чтобы понять, как это выяснить.
typedef union {
int i;
double d;
long l;
char s[16];
} data_unit;
Ваш союз имеет:
int i
, который мы предполагаем равным 4 байта
double d
, что составляет 8 байтов
long l
, что сбивает с толку, потому что в зависимости от компилятора / платформы может быть 4 или 8 байтов, мы предполагаем 8 байтов на данный момент.
char s[16]
, легкий, 16 байтов
Таким образом, наибольшее количество байтов, которое занимает любой член, это ваша переменная char s[16]
, 16 байтов. Это означает, что вам нужно изменить код на:
int data_size;
int union_size = 16;
CUdeviceptr d_array;
// copying this to the device will not result in what you expect with out over allocating
// if you just copy over integers, which occupy 4 bytes each, your integers will fill less space than the number of unions
// we need to make sure that there is a "stride" here if we want to actually copy real data from host to device.
// union_size / Sizeof.INT = 4, so there will be 4 x as many ints, 4 for each union.
int[] h_array = new int[data_size * (union_size / Sizeof.INT)];
// here we aren't looking for size of int to allocate, but the size of our union.
cuMemAlloc(d_array, data_size * union_size);
// we are copying, again, data_size * union_size bytes
cuMemcpyHtoD(d_array, Pointer.to(h_array), data_size * union_size);
Примечание
Если вы хотите скопировать целые числа, это в основном означает, что вам нужно будет присваивать каждые 4-е целые числа фактическому целому числу, которое вы хотите для этого индекса.
int 0 равно h_array[0]
, int 1 равно h_array[4]
int 2 равно h_array[8]
int n равно h_array[n * 4]
и т. Д.