:それは、このコードを使用して起動さこれはCUDAのバグですか? (不正なメモリアクセスが発生しました)
__global__
void sum_worker(int *data, int *sum_ptr)
{
__shared__ int block_sum;
int idx = threadIdx.x;
int thread_sum = 0;
if (threadIdx.x == 0)
block_sum = 2;
for (int i = idx; i < MAX_INDEX; i += blockDim.x)
thread_sum += data[i];
__syncthreads();
atomicAdd(&block_sum, thread_sum);
__syncthreads();
if (threadIdx.x == 0)
*sum_ptr = block_sum;
}
:
sum_worker<<<1, 32>>>(primes_or_zeros, sum_buffer);
そして、それが働いているファイン(無ランタイムエラーをして生成します正しい結果)。
Cuda error 'an illegal memory access was encountered' in primes_gpu.cu at line 97
cuda-memcheck
でカーネルを実行している:
========= Invalid __global__ read of size 4
========= at 0x00000108 in /home/clifford/Work/handicraft/2016/perfmeas/primes_gpu.cu:35:sum_worker(int*, int*)
========= by thread (31,0,0) in block (0,0,0)
========= Address 0x703b70d7c is out of bounds
========= Saved host backtrace up to driver entry point at kernel launch time
========= Host Frame:/usr/lib/x86_64-linux-gnu/libcuda.so.1 (cuLaunchKernel + 0x2c5) [0x472225]
========= Host Frame:/usr/lib/x86_64-linux-gnu/libcudart.so.7.5 [0x146ad]
========= Host Frame:/usr/lib/x86_64-linux-gnu/libcudart.so.7.5 (cudaLaunch + 0x143) [0x2ece3]
========= Host Frame:./perfmeas [0x17c7]
========= Host Frame:./perfmeas [0x16b7]
========= Host Frame:./perfmeas [0x16e2]
========= Host Frame:./perfmeas [0x153f]
========= Host Frame:./perfmeas [0xdcd]
========= Host Frame:/lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main + 0xf0) [0x20830]
========= Host Frame:./perfmeas [0xf39]
....
アドレス0x703b70d7cがdata
の境界の外に確かにある:私はi += blockDim.x
i += 32
に変更した場合しかし、私はエラー私はcudaDeviceSynchronize()
呼び出す次の時間を取得します配列は0x703b40000から始まり、MAX_INDEX要素を持ちます。このテストでMAX_INDEXは50000です。これはCUDAのバグです
for (int i = idx; i < MAX_INDEX; i += 32) {
if (i >= MAX_INDEX)
printf("WTF!\n");
thread_sum += data[i];
}
または私はここに愚かな何かをやっている: - (0x703b70d7c 0x703b40000)/ 4 = 50015.
がi >= 50000
のための追加のチェックを追加するには、魔法のように離れて行く問題になりますか?
私はUbuntu 2016.04でCUDA 7.5を使用しています。 nvcc --version
の出力:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2015 NVIDIA Corporation
Built on Tue_Aug_11_14:27:32_CDT_2015
Cuda compilation tools, release 7.5, V7.5.17
このテストケースのための完全なソースコードはここで見つけることができます:
http://svn.clifford.at/handicraft/2016/perfmeas
(オプション-gx
で実行します。このバージョンはi += blockDim.x
を使用している再現するi += 32
にそれを変更します。 )
編集:@njuffaは、彼はリンクオフにリンクしたくない彼は "コンピュータが何かを捕まえるかもしれない"と恐怖を感じており、&のペーストを直接スタックオーバーフローからコピーできるというテストケースを好むからです。だからここには行く:
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#define MAX_PRIMES 100000
#define MAX_INDEX (MAX_PRIMES/2)
__global__
void primes_worker(int *data)
{
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (idx >= MAX_INDEX)
return;
int p = 2*idx+1;
for (int i = 3; i*i <= p; i += 2) {
if (p % i == 0) {
data[idx] = 0;
return;
}
}
data[idx] = idx ? p : 0;
}
__global__
void sum_worker(int *data, int *sum_ptr)
{
__shared__ int block_sum;
int idx = threadIdx.x;
int thread_sum = 0;
if (threadIdx.x == 0)
block_sum = 2;
#ifdef ENABLE_BUG
for (int i = idx; i < MAX_INDEX; i += 32)
thread_sum += data[i];
#else
for (int i = idx; i < MAX_INDEX; i += blockDim.x)
thread_sum += data[i];
#endif
__syncthreads();
atomicAdd(&block_sum, thread_sum);
__syncthreads();
if (threadIdx.x == 0)
*sum_ptr = block_sum;
}
int *primes_or_zeros;
int *sum_buffer;
void primes_gpu_init()
{
cudaError_t err;
err = cudaMalloc((void**)&primes_or_zeros, sizeof(int)*MAX_INDEX);
if (err != cudaSuccess)
printf("Cuda error '%s' in %s at line %d\n", cudaGetErrorString(err), __FILE__, __LINE__);
err = cudaMallocHost((void**)&sum_buffer, sizeof(int));
if (err != cudaSuccess)
printf("Cuda error '%s' in %s at line %d\n", cudaGetErrorString(err), __FILE__, __LINE__);
}
void primes_gpu_done()
{
cudaError_t err;
err = cudaFree(primes_or_zeros);
if (err != cudaSuccess)
printf("Cuda error '%s' in %s at line %d\n", cudaGetErrorString(err), __FILE__, __LINE__);
err = cudaFreeHost(sum_buffer);
if (err != cudaSuccess)
printf("Cuda error '%s' in %s at line %d\n", cudaGetErrorString(err), __FILE__, __LINE__);
}
int primes_gpu()
{
int num_blocks = (MAX_INDEX + 31)/32;
int num_treads = 32;
primes_worker<<<num_blocks, num_treads>>>(primes_or_zeros);
sum_worker<<<1, 32>>>(primes_or_zeros, sum_buffer);
cudaError_t err = cudaDeviceSynchronize();
if (err != cudaSuccess)
printf("Cuda error '%s' in %s at line %d\n", cudaGetErrorString(err), __FILE__, __LINE__);
return *sum_buffer;
}
int main()
{
primes_gpu_init();
int result = primes_gpu();
printf("Result: %d\n", result);
if (result != 454396537) {
printf("Incorrect result!\n");
return 1;
}
primes_gpu_done();
return 0;
}
使用法:
$ nvcc -o demo demo.cu
$ ./demo
Result: 454396537
$ nvcc -D ENABLE_BUG -o demo demo.cu
$ ./demo
Cuda error 'an illegal memory access was encountered' in demo.cu at line 99
Result: 0
Incorrect result!
(http://stackoverflow.com/help/mcve)あなたはここに誰を見つけることはほとんどありませんさえを支援しようとしますあなたのコードをデバッグする。 – njuffa
@njuffa投稿したリンクで利用可能なコードを見たことがありますか?それは確かに完全で検証可能です。それはまた、最小に近い。 – CliffordVienna
MCVEの基本的な意味:SOユーザーはソースコードをカットしてお気に入りのエディタに貼り付け、ファイルを保存してコンパイルして実行することができます。私が言うことができる最高の、これは上記のコードでは不可能です。私は通常オフサイトのリンクに従いません(私のコンピュータが何かを捕まえるかもしれないことを恐れています)。 – njuffa