Примечание 4
Итак, код окончательно исправлен! Оказалось, что последняя проблема заключалась в том, что я добавлял размер пространства, выделенного каждому массиву, в ptr, но c уже учитывает размер переменной, поэтому я, по сути, добавил в 4 раза больше места в байтах, чем следовало бы был, следовательно, будут отображаться только первые два элемента в массиве из 5 элементов. AoSoA
теперь полностью работает. Будьте осторожны с вашей запиской управление, если вы попробуете что-то подобное, я боролся с множеством, казалось бы, глупых ошибок, потому что мой исходный код был неаккуратным.
Осторожно:
+ Неправильные смещения
+ Ненужный Маллок
+ Недопустимые ссылки
Вот рабочий пример кода, результаты следуют!
#include <stdio.h>
#define REGIONS 20
#define YEARS 5
__inline __host__ void gpuAssert(cudaError_t code, char *file, int line,
bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code),
file, line);
if (abort) exit(code);
}
}
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
struct AnimalPopulationForYear_s
{
bool isYearEven;
int * rabbits;
int * hyenas;
};
AnimalPopulationForYear_s * dev_pop;
__global__ void RunSim(AnimalPopulationForYear_s dev_pop[],
int year)
{
int idx = blockIdx.x*blockDim.x+threadIdx.x;
int rabbits, hyenas;
int arrEl = year-1;
rabbits = (idx+1) * year * year;
hyenas = rabbits / 10;
if ( rabbits > 100000 ) rabbits = 100000;
if ( hyenas < 2 ) hyenas = 2;
if ( idx < REGIONS ) dev_pop[arrEl].rabbits[idx] = rabbits;
if ( idx < REGIONS ) dev_pop[arrEl].hyenas[idx] = hyenas;
if (threadIdx.x == 0 && blockIdx.x == 0)
dev_pop[arrEl].isYearEven = (year & 0x01 == 0x0);
}
int main()
{
//Various reused sizes...
const size_t fullArrSz = size_t(YEARS) * size_t(REGIONS) * sizeof(int);
const size_t structArrSz = size_t(YEARS) * sizeof(AnimalPopulationForYear_s);
//Vars to hold struct and merged subarray memory inside it.
AnimalPopulationForYear_s * h_pop;
int * dev_hyenas, * dev_rabbits, * h_hyenas, * h_rabbits, arrEl;
//Alloc. memory.
h_pop = (AnimalPopulationForYear_s *) malloc(structArrSz);
h_rabbits = (int *) malloc(fullArrSz);
h_hyenas = (int *) malloc(fullArrSz);
gpuErrchk(cudaMalloc((void **) &dev_pop,structArrSz));
gpuErrchk(cudaMalloc((void **) &dev_rabbits,fullArrSz));
gpuErrchk(cudaMalloc((void **) &dev_hyenas,fullArrSz));
//Offset ptrs.
for (int i = 0; i < YEARS; i++)
{
h_pop[i].rabbits = dev_rabbits+i*REGIONS;
h_pop[i].hyenas = dev_hyenas+i*REGIONS;
}
//Copy host struct with dev. pointers to device.
gpuErrchk
(cudaMemcpy(dev_pop,h_pop, structArrSz, cudaMemcpyHostToDevice));
//Call kernel
for(int i=1; i < YEARS+1; i++) RunSim<<<REGIONS/128+1,128>>>(dev_pop,i);
//Make sure nothing went wrong.
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());
gpuErrchk(cudaMemcpy(h_pop,dev_pop,structArrSz, cudaMemcpyDeviceToHost));
gpuErrchk
(cudaMemcpy(h_rabbits, dev_rabbits,fullArrSz, cudaMemcpyDeviceToHost));
gpuErrchk(cudaMemcpy(h_hyenas,dev_hyenas,fullArrSz, cudaMemcpyDeviceToHost));
for(int i=0; i < YEARS; i++)
{
h_pop[i].rabbits = h_rabbits + i*REGIONS;
h_pop[i].hyenas = h_hyenas + i*REGIONS;
}
for(int i=1; i < YEARS+1; i++)
{
arrEl = i-1;
printf("\nYear %i\n=============\n\n", i);
printf("Rabbits\n-------------\n");
for (int j=0; j < REGIONS; j++)
printf("Region: %i Pop: %i\n", j, h_pop[arrEl].rabbits[j]);;
printf("Hyenas\n-------------\n");
for (int j=0; j < REGIONS; j++)
printf("Region: %i Pop: %i\n", j, h_pop[arrEl].hyenas[j]);
}
//Free on device and host
cudaFree(dev_pop);
cudaFree(dev_rabbits);
cudaFree(dev_hyenas);
free(h_pop);
free(h_rabbits);
free(h_hyenas);
return 0;
}
[Наконец] правильные результаты:
Год 1
=============
Кролики
-------------
Регион: 0 Поп: 1
Регион: 1 Поп: 2
Регион: 2 Поп: 3
Регион: 3 Поп: 4
Регион: 4 Поп: 5
Регион: 5 Поп: 6
Регион: 6 Поп: 7
Регион: 7 Поп: 8
Регион: 8 Поп: 9
Регион: 9 Поп: 10
Регион: 10 Поп:
11
Регион: 11 Поп: 12
Регион: 12 Поп: 13
Регион: 13
Поп: 14
Регион: 14 Поп: 15
Регион: 15 Поп: 16
Регион:
16 Поп: 17
Регион: 17 Поп: 18
Регион: 18 Поп: 19
Регион: 19 Поп: 20
Гиены
-------------
Регион: 0 Поп: 2
Регион: 1 Поп: 2
Регион: 2 Поп: 2
Регион: 3 Поп: 2
Регион: 4 Поп: 2
Регион: 5 Поп: 2
Регион: 6 Поп: 2
Регион: 7 Поп: 2
Регион: 8 Поп: 2
Регион: 9 Поп: 2
Регион: 10 Поп: 2
Регион: 11 Поп: 2
Регион: 12 Поп: 2
Регион: 13 Поп:
2
Регион: 14 Поп: 2
Регион: 15 Поп: 2
Регион: 16
Поп: 2
Регион: 17 Поп: 2
Регион: 18 Поп: 2
Регион: 19
Поп: 2
Год 2
=============
Кролики
-------------
Регион: 0 Поп: 4
Регион: 1 Поп: 8
Регион: 2 Поп: 12
Регион: 3 Поп: 16
Регион: 4 Поп:
20
Регион: 5 Поп: 24
Регион: 6 Поп: 28
Регион: 7
Поп: 32
Регион: 8 Поп: 36
Регион: 9 Поп: 40
Регион:
10 Поп: 44
Регион: 11 Поп: 48
Регион: 12 Поп: 52
Регион: 13 Поп: 56
Регион: 14 Поп: 60
Регион: 15 Поп:
64
Регион: 16 Поп: 68
Регион: 17 Поп: 72
Регион: 18
Поп: 76
Регион: 19 Поп: 80
Гиены
-------------
Регион: 0 Поп: 2
Регион: 1 Поп: 2
Регион: 2 Поп: 2
Регион: 3 Поп: 2
Регион: 4 Поп: 2
Регион: 5 Поп: 2
Регион: 6 Поп: 2
Регион: 7 Поп: 3
Регион: 8 Поп: 3
Регион: 9 Поп: 4
Регион: 10 Поп: 4
Регион: 11 Поп: 4
Регион: 12 Поп: 5
Регион: 13 Поп:
5
Регион: 14 Поп: 6
Регион: 15 Поп: 6
Регион: 16
Поп: 6
Регион: 17 Поп: 7
Регион: 18 Поп: 7
Регион: 19
...
Примечание 3:
После talonmies исправлено несколько несоответствий индексации массивов и т. Д. В моем коде.
Результаты выглядят как правильные SoA для первых двух точек в AoSoA (см. Новый вывод). По какой-то причине результаты с третьего места (year 3
) теперь дают неверные результаты, хотя код ошибки от GPU отсутствует. Я собираюсь посмотреть на указатели (h_pop[year-1].rabbits
, h_pop[year-1].hyenas
) и посмотреть, покажет ли это что-нибудь.
Мой единственный совет для всех, кто пытается AoSoA - быть ОЧЕНЬ осторожным с индексацией и распределением памяти. Конечно, это хороший совет в целом, но, когда вся память летит в сложном многоуровневом контейнере данных, таком как AoSoA, тенденция к ошибкам, если вы небрежны, экспоненциально возрастает. Спасибо за ваше терпение, talonmies .
Примечание 2:
Поэтому, следуя совету talonmies , я исправил свой цикл #ing, обернул свои cuda-вызовы w. проверка ошибок и сжала мои cudaMemcpy
звонки путем повторного использования dev_rabbits
/ dev_hyenas
. Также переключил регистр на первую букву в нижнем регистре, так как я думал о жалобе [djmj] [4] на регистр, и я понял, что NVIDIA делает строчные буквы первой буквы в своих константах, поэтому [djmj] [4] Правильно, в некотором смысле, я должен был сделать свой код таким, чтобы он был согласованным, независимо от моих личных предпочтений / опыта.
Также, как правило, очищал код, так как я написал, что он не спал и был немного испуган @ как неряшливо это было.
Теперь я сталкиваюсь с новой проблемой ... моя программа зависает при первом cudaMemcpy
и не возвращает (следовательно, удобная оболочка talonmies не ловит что-нибудь). Я не совсем уверен, почему это так ... Я скомпилировал на устройстве несколько программ, в том числе гораздо больших и более продолжительных, и все они работают нормально.
На данный момент я озадачен. Если он все еще не работает, возможно, отправьте что-нибудь утром.
Примечание 1
Первый ответ, казалось, действительно упускал суть. Это всего лишь игрушечный код, он не предназначен для представления реальной программы. Его единственная цель - попытаться настроить память, записать в нее немного мусора и прочитать его обратно, чтобы убедиться, что AoSoA работает.
Так что комментировать мне общую память и т. Д. Не будет продуктивным. Не в этом суть этой темы. Конечно, если бы это был настоящий код, я бы исключил разветвления в своих ядрах, использовал разделяемую память, выровнял свои данные, использовал суммирование уровня деформации и т. Д. Я сделал все это в предыдущих кодах и заставил его работать.
Этот код является игрушкой, доказательством концептуального кода, не более и не менее, разработанным для того, чтобы попытаться заставить AoSoA работать. Это его единственная цель, это не настоящий код. это подтверждение концепции.
Что касается размещения имен переменных, я работал в двух разных местах, которые использовали полностью покрытые имена переменных в своем стандарте кодирования (они использовали теги, я делаю _s
для structs / typedefs), так что застрял. Извините, вам не нравится это. Что касается отступа, я постараюсь исправить это позже ... Windows и Linux не играли хорошо.
Еще одно замечание: если вас смущает смещение указателя устройства, см. Ответ Anycom здесь:
Указатели в структурах переданы CUDA
Я написал следующий код для проверки массивов структур с массивами внутри в CUDA ....
Редактировать: Исправлен код - зависает после meh
и до hi
, предположительно на cudaMemcpy
... не знаю почему!
... Есть идеи, что здесь происходит и как это исправить?
Примечание:
Я волновался, что cudaFree
могут испортить вещи, но удаление их ничего не сделало.
[4]: