【发布时间】:2016-12-08 14:28:33
【问题描述】:
我正在启动一个带有 512 个线程的线性块的内核。与每个线程相关的是六个双精度值(两个 3 元素向量),我想将它们存储在共享内存中,总共 512*6*8=24576 字节。我想创建指向 shared 的中间元素的指针,以将所有向量排列如下:
__global__ void my_kernel(double *global_data) {
extern __shared__ double shr[];
id = threadIdx.x;
double *X = &shr[id*3];
double *Y = &shr[(id+1)*3];
// Some arithmetic to set X[0:3] ad Y[0:3]
// Now I have a small for loop to compute something for each thread
for (int i = 0; i < 3; i++) {
for (int j=0; j < 3; j++) {
// Some computations involving the X and Y vectors
}
}
我的问题是使用循环索引访问 X 和 Y 中的值。在第一次循环迭代期间,我无法解释以下行为:
(cuda-gdb) cuda thread
thread (0,0,0)
(cuda-gdb) p shr[0]
$1 = 0.62293193093894383
(cuda-gdb) p &shr[0]
$2 = (@shared double *) 0x0
(cuda-gdb) p X[0]
$3 = 0.62293193093894383
(cuda-gdb) p &X[0]
$4 = (@generic double *) 0x1000000
(cuda-gdb) p X
$5 = (@generic double * @register) 0x1000000
我认为这很正常。但后来:
(cuda-gdb) p i == 0
$7 = true
(cuda-gdb) p X[i]
Error: Failed to read global memory at address 0x0 on device 0 sm 0 warp 0 lane 0 (error=7).
为什么当 i == 0 时我可以访问 X[0] 而不能访问 X[i]?
编辑:这是一个完整的工作示例,展示了我的问题:
import pycuda.gpuarray as gpuarray
import pycuda.driver as cuda
import pycuda.autoinit
import numpy as np
from pycuda.compiler import SourceModule
from math import pi
mydat = np.arange(12).astype(np.float64)
mydat_gpu = gpuarray.to_gpu(mydat)
mod = SourceModule("""
__global__ void my_kernel(double *mydat) {
extern __shared__ double shr[];
int id = threadIdx.x;
double *X = &shr[(id * 6)];
double *Y = &shr[(id * 6) + 3];
X[0] = mydat[0];
X[1] = mydat[1];
X[2] = mydat[2];
Y[0] = mydat[3];
Y[1] = mydat[4];
Y[2] = mydat[5];
__syncthreads();
double result;
for (int i = 0; i < 3; i++) {
result += X[i] + Y[i];
}
}
""")
my_kernel = mod.get_function("my_kernel")
blk = (1,1,1)
grd = (1,1,1)
my_kernel(mydat_gpu, grid=grd, block=blk, shared=(8*6))
此时我启动了一个调试会话:
cuda-gdb --args python -m pycuda.debug minimal_working_example.py
(cuda-gdb) b my_kernel
Function "my_kernel" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (my_kernel) pending.
(cuda-gdb) run
[Switching focus to CUDA kernel 0, grid 1, block (0,0,0), thread (0,0,0), device 0, sm 0, warp 0, lane 0]
Breakpoint 1, my_kernel(double * @generic)<<<(1,1,1),(1,1,1)>>> (mydat=0x13034a0000)
at kernel.cu:5
5 int id = threadIdx.x;
(cuda-gdb) n
7 double *X = &shr[(id * 6)];
(cuda-gdb) p id
$1 = 0
(cuda-gdb) p id * 6
$2 = 0
(cuda-gdb) n
8 double *Y = &shr[(id * 6) + 3];
(cuda-gdb) p (id * 6) + 3
$3 = 3
(cuda-gdb) n
10 X[0] = mydat[0];
(cuda-gdb) n
11 X[1] = mydat[1];
(cuda-gdb) n
12 X[2] = mydat[2];
(cuda-gdb) n
13 Y[0] = mydat[3];
(cuda-gdb) n
14 Y[1] = mydat[4];
(cuda-gdb) n
15 Y[2] = mydat[5];
(cuda-gdb) p X
$4 = (@generic double * @register) 0x1000000
(cuda-gdb) p X[0]
$5 = 0
(cuda-gdb) p X[1]
$6 = 1
(cuda-gdb) p Y[0]
$7 = 3
(cuda-gdb) p Y[1]
$8 = 4
(cuda-gdb) n
18 __syncthreads();
(cuda-gdb) n
22 for (int i = 0; i < 3; i++) {
(cuda-gdb) n
23 result += X[i] + Y[i];
(cuda-gdb) p i
$9 = 0
(cuda-gdb) p X[0]
$10 = 0
(cuda-gdb) p X[i]
Error: Failed to read global memory at address 0x0 on device 0 sm 0 warp 0 lane 0 (error=7).
【问题讨论】:
-
??这:
extern __shared__ shr[];不是有效的 CUDA C/C++。 -
对不起@RobertCrovella 我昨晚有点仓促地输入了这个 - 在产生问题的代码中它被声明为
extern __shared__ double shr[];我正在更新 OP 以反映这一点。 -
一般来说,很难解释我们尚未展示的代码的运行时行为。您对
X和Y的索引计算显然不正确(线程 id = 0 的 Y 与线程 id = 1 的 X 相同),但是如果没有 minimal reproducible example,就不可能说其他可能出错的地方.如果你不能提供,我怀疑你会得到答案 -
您的指令指针在上面显示的各种
cuda-gdb命令中的位置也不清楚。我假设你在内核代码的某个地方设置了一个断点。但是根据您在代码中的位置,即使使用-G编译,变量也可能在范围内或范围外,并且尝试访问范围外变量(例如局部变量)会产生不一致的结果。一个完整的代码和一个完整的 gdb 会话显示你所做的事情可能是解释任何事情所必需的。 -
作为一般规则,您不应该花太多时间思考、处理或使用工具来分析不修改任何全局状态的代码。