Использование CUB::DeviceScan
Я пытаюсь сделать эксклюзивное сокращение суммы в CUDA. Я использую библиотеку CUB и решил попробовать CUB::DeviceReduce. Тем не менее, мой результат NaN, и я не могу понять, почему.
Код является:
#include <cub/cub.cuh>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
#define DSIZE 512
void dev_cumsum( const float *dev_inData, float *dev_outData ) {
int n = 512;
void* dev_temp_storage = NULL;
size_t temp_storage_bytes = 0;
cub::DeviceScan::ExclusiveSum(dev_temp_storage,temp_storage_bytes,const_cast<float*>(dev_inData),dev_outData,n);
cudaMalloc(&dev_temp_storage,temp_storage_bytes);
cub::DeviceScan::ExclusiveSum(dev_temp_storage,temp_storage_bytes,const_cast<float*>(dev_inData),dev_outData,n);
}
int main(){
float h_data[512];
float* d_data;
float* d_result;
float h_result[512];
cudaMalloc(&d_data, DSIZE*sizeof(float));
cudaMalloc(&d_result, DSIZE*sizeof(float));
h_data[0] = rand()%10;
h_result[0] = 0;
for (int i=1; i<DSIZE; i++) {
h_data[i] = rand()%10;
h_result[i] = h_data[i-1]+h_result[i-1];
}
cudaMemcpy(d_data, h_data, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
dev_cumsum(d_data, d_result);
printf("CPU result = %f\n", h_result[511]);
cudaMemcpy(h_result, d_result, DSIZE*sizeof(float), cudaMemcpyDeviceToHost);
printf("GPU result = %f\n", h_result[511]);
for( int i = 0; i < DSIZE; i++ ) {cout << h_result[i] << " ";}
cout << endl;
return 0;
}
Этот код дает мне NaN за последние 8 элементов результата устройства.
Этот код работает на GTX650 Ti Boost в Linux Mint15. Я использую NSight и консольная команда вывода:
Invoking: NVCC Compiler
/usr/local/cuda-5.5/bin/nvcc -G -g -O0 -gencode arch=compute_30,code=sm_30 -odir "" -M -o "main.d" "../main.cu"
/usr/local/cuda-5.5/bin/nvcc --device-c -G -O0 -g -gencode arch=compute_30,code=compute_30 -gencode arch=compute_30,code=sm_30 -x cu -o "main.o" "../main.cu"
Cuda версия 5.5 CUB версия 1.0.2
Это было проверено на другом компьютере с Cuda 6, OSX10.9.2, CUB 1.2.3 и GT750M, и воспроизвел ошибку последних 8 чисел, являющуюся NaN
редактировать: код работает правильно с int и double, но не с плавающей точкой.
редактирование: благодаря Роберту Кровелле этот вопрос изначально задавался в отношении DeviceReduce. Этот код работал, он выдавал NaN, потому что предыдущий код, использующий DeviceScan, подавал ему NaN в качестве входных данных. Вопрос пересмотрен в соответствии с
2 ответа
РЕДАКТИРОВАТЬ: Cub 1.3.0 был недавно выпущен, и я считаю, что он включает в себя исправление этой проблемы.
Я внесу несколько изменений в ваш код, которые я считаю ошибками, но я не знаю, влияют ли они на то, что вы видите. В следующем разделе кода вы используете h_result[0]
без инициализации, поэтому добавьте строку, которую я пометил комментарием:
h_data[0] = rand()%10;
h_result[0] = 0; // ADD THIS LINE
for (int i=1; i<DSIZE; i++) {
h_data[i] = rand()%10;
h_result[i] = h_data[i-1]+h_result[i-1];
}
(Понятно, что никто не должен влиять на ваш результат GPU.) Кроме того, ваш окончательный cudaMemcpy
операция не совсем правильная
cudaMemcpy(&h_result, d_result, DSIZE*sizeof(float), cudaMemcpyDeviceToHost);
^
delete this ampersand
поскольку h_result
это уже указатель в вашей формулировке, нам не нужно передавать его адрес cudaMemcpy
,
Можете ли вы попробовать внести эти изменения и посмотреть, какие результаты вы получите?
Я немного боролся с этим. Если вы все еще можете воспроизвести ошибку, я буду признателен, если вы сможете:
- перезагрузите компьютер и попробуйте снова
- ответьте актуальным обновленным кодом, который вы используете, командой компиляции, версией CUDA, версией CUB и графическим процессором, на котором вы работаете, а также операционной системой системы. (отредактируйте исходный вопрос с помощью этой информации)
Когда я запустил код, я обнаружил, что это не последние 8 значений, которые установлены в NaN, но это, фактически, все значения, начиная с последнего целого числа, кратного 72, которые установлены в NaN. В вашем примере есть 512 значений: это означает, что первые 504 (7 * 72) были правильными, а следующие 8 значений были NaN.
Такое поведение, кажется, продолжается до 568 (8 * 72) значений и после этого, кажется, работает правильно.
Код, который я использовал для проверки этого, находится здесь: http://pastebin.com/kXVvuKAN
Я скомпилировал код с помощью следующей команды:
nvcc --relocatable-device-code = true -gencode arch = compute_30, code = compute_30 -G -o main main.cu
ПРИМЕЧАНИЕ. Если я не использовал параметр -G, результаты были более случайными. Однако с помощью команды -G он дал четкую схему, упомянутую выше.