我是cuda的新手,我正试图用它来执行Eratosthenes的筛子。该代码适用于低于1000000的素数。在它上面我得到一个未知的内核启动错误。现在我明白这是因为我试图启动一个包含太多块的网格。但是,如果我将块设置为1000,则不会获得所有素数。我认为内核中的索引可能存在问题,但不确定。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
using namespace std;
__global__ static void Sieve(long * sieve, long sieve_size)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx > 1) {
for (int i = idx+idx; i < sieve_size; i += idx) {
sieve[i] = 1;
}
}
}
int main()
{
long *device_sieve;
long *host_sieve = new long[4000000];
ofstream data("data.csv", ofstream::out);
double sieve_size = 4000000 / sizeof(long);
cudaSetDevice(0);
cudaDeviceSynchronize();
cudaThreadSynchronize();
cudaMalloc((void**)&device_sieve, sizeof(long) * sieve_size);
cudaError_t error1 = cudaGetLastError();
cout << "1" << cudaGetErrorString(error1) << endl;
int block = sqrt(sieve_size);
Sieve << <1, block >> >(device_sieve, sieve_size);
cudaThreadSynchronize();
cudaMemcpy(host_sieve, device_sieve, sizeof(long) * sieve_size, cudaMemcpyDeviceToHost);
cudaError_t error = cudaGetLastError();
cout << "2" << cudaGetErrorString(error) << endl;
cudaFree(device_sieve);
for (int i = 2; i < sieve_size; ++i)
if (host_sieve[i] == 0)
data << i << endl;
getchar();
cout << "DONE" << endl;
return 0;
}
答案 0 :(得分:1)
我发现您的代码存在一些问题。首先,行double sieve_size = 4000000 / sizeof(long);
没有意义,因为这会导致在GPU上分配不足的内存量。
举一个8个数字的例子,每个8个字节长(这是long afaik的标准大小),所以将它们放入一个数组需要64个字节的内存。这意味着您的double sieve_size = 8/sizeof(long)
将保留值1
。然后你在GPU上分配sieve_size*sizeof(long)
个字节的内存,在这种情况下意味着你要分配8个字节,而在初始数组中你需要64个字节。所以放弃师。
另一件事是我不认为使用double
表示一定数量的内存是好主意,即使它可能不会产生编译错误,也可能导致精度问题舍入,当你只分配几个字节太少而因此调用分段错误时(如果你需要表示离散实体,例如内存块的大小或数组的长度,整数类型是合乎逻辑的选择)。所以我会改行:
long sieve_size = 4000000;
现在另一件事是你可以执行的块的大小有限制。它因架构而异,您可以找到使用命令cudaGetDeviceProperties
的具体内容。据我所知,在大多数现代卡片上,限制是1024 max threads per block
。因此,您可以执行大小为32x32x1
或1024x1x1
的块。如果您需要处理更多数据,则必须使用比1x1x1
更大的网格。
希望这有帮助!