CUDA - большое количество и выделение памяти
У меня очень странная ошибка в программе. Я потратил много часов на это, но я не нашел решения. Я написал простую программу, чтобы воспроизвести мою проблему. Может быть, кто-то поможет мне. Я попробовал cuda-memcheck & Каков канонический способ проверки на ошибки с использованием API времени выполнения CUDA? но я не получаю никаких ошибок.
Подробности:
Версия nvcc - V6.0.1
версия gcc - 4.8.1
Полный код:
#include <stdio.h>
__constant__ unsigned long long int bigNumber = 83934243334343;
__device__ bool isFound = false;
__global__ void kernel(int *dev_number) {
unsigned long long int id = threadIdx.x + (blockIdx.x * blockDim.x);
while (id < bigNumber && isFound==false) {
if(id == 10) {
*dev_number = 4;
isFound=true;
}
id++;
}
}
int main(int argc, char *argv[]) {
int number = 0;
int *dev_number;
printf("Number: %d\n", number);
return 0;
}
Компиляция и запуск:
nvcc myprogram.cu
./myprogram
Когда я запускаю эту программу, я не получаю никакого возвращаемого значения. Но когда переменная - bigNumber имеет меньшее значение, или я не использую cudaMalloc & cudaMemcpy, это работает (это означает, что вызывается return 0). Какое соединение должно выделять память для другой переменной с константой bigNumber? В чем проблема?
1 ответ
Теперь, когда вы изменили код на что-то более разумное, я сразу же получу следующую модификацию:
__device__ volatile bool isFound = false;
volatile
квалификатор вынуждает компилятор пропускать любые оптимизации, которые мешали бы каждому потоку читать глобальную копию переменной.
Из документации
Компилятор может оптимизировать операции чтения и записи в глобальную или разделяемую память (например, путем кэширования глобальных операций чтения в регистры или кэш-память L1), если он соблюдает семантику упорядочения памяти в функциях ограничения памяти (Memory Fence Functions) и семантику видимости памяти. функций синхронизации (Synchronization Functions).
Эти оптимизации можно отключить с помощью ключевого слова volatile: если переменная, расположенная в глобальной или разделяемой памяти, объявлена как volatile, компилятор предполагает, что ее значение может быть изменено или использовано в любой момент другим потоком, и поэтому любая ссылка на эту переменную компилируется в фактическая инструкция чтения или записи в памяти.
Если вы не можете использовать volatile
квалификатор, тогда только один поток принимает условие раннего выхода (isFound
) и все остальные должны зацикливаться очень долго, пока их id
значение превышает bigNumber