CUDA 分析 - 高共享 transactions/access 但本地重放率低
CUDA profiling - high shared transactions/access but low local replay rate
在 运行 Visual Profiler 之后,引导分析告诉我我受内存限制,尤其是我的共享内存访问很差 aligned/accessed - 基本上我访问共享内存的每一行被标记为每次访问 ~2 个事务。
但是,我想不通为什么会这样(我的共享内存是padded/strided所以不应该有银行冲突),所以我回去检查了共享重播指标 - 表明只有 0.004% 的共享访问被重播。
那么,这是怎么回事,我应该注意什么来加速我的内核?
编辑:最小复制:
import numpy as np
import pycuda.autoinit
import pycuda.driver as cuda
from pycuda.compiler import SourceModule
import pycuda.gpuarray as gp
mod = SourceModule("""
(拆分代码块以获得 Python 和 CUDA/C++ 着色)
typedef unsigned char ubyte;
__global__ void identity(ubyte *arr, int stride)
{
const int dim2 = 16;
const int dim1 = 64;
const int dim0 = 33;
int shrstrd1 = dim2;
int shrstrd0 = dim1 * dim2;
__shared__ ubyte shrarr[dim0 * dim1 * dim2];
auto shrget = [shrstrd0, shrstrd1, &shrarr](int i, int j, int k) -> int{
return shrarr[i * shrstrd0 + j * shrstrd1 + k];
};
auto shrset = [shrstrd0, shrstrd1, &shrarr](int i, int j, int k, ubyte val) -> void {
shrarr[i * shrstrd0 + j * shrstrd1 + k] = val;
};
int in_x = threadIdx.x;
int in_y = threadIdx.y;
shrset(in_y, in_x, 0, arr[in_y * stride + in_x]);
arr[in_y * stride + in_x] = shrget(in_y, in_x, 0);
}
""",
(同上)
options=['-std=c++11'])
#Equivalent to identity<<<1, dim3(32, 32, 1)>>>(arr, 64);
identity = mod.get_function("identity")
identity(gp.zeros((64, 64), np.ubyte), np.int32(64), block=(32, 32, 1))
每次访问 2 个事务,共享重放开销 0.083。将 dim2
减少到 8 会使问题消失,我也不明白。
部分回答:我对共享内存库的工作方式存在根本性的误解(即,它们是 banks,每个大约有一千个字节库),所以没有意识到它们是循环的,所以过多的填充意味着 32 行元素最终可能会不止一次地使用每个 bank。
不过,据推测,这种冲突并不是每次都出现 - 相反,它出现了,哦,从数字来看,一个区块大约出现 85 次。
我会把它留在这里一天,希望得到更完整的解释,然后关闭并接受这个答案。
在 运行 Visual Profiler 之后,引导分析告诉我我受内存限制,尤其是我的共享内存访问很差 aligned/accessed - 基本上我访问共享内存的每一行被标记为每次访问 ~2 个事务。
但是,我想不通为什么会这样(我的共享内存是padded/strided所以不应该有银行冲突),所以我回去检查了共享重播指标 - 表明只有 0.004% 的共享访问被重播。
那么,这是怎么回事,我应该注意什么来加速我的内核?
编辑:最小复制:
import numpy as np
import pycuda.autoinit
import pycuda.driver as cuda
from pycuda.compiler import SourceModule
import pycuda.gpuarray as gp
mod = SourceModule("""
(拆分代码块以获得 Python 和 CUDA/C++ 着色)
typedef unsigned char ubyte;
__global__ void identity(ubyte *arr, int stride)
{
const int dim2 = 16;
const int dim1 = 64;
const int dim0 = 33;
int shrstrd1 = dim2;
int shrstrd0 = dim1 * dim2;
__shared__ ubyte shrarr[dim0 * dim1 * dim2];
auto shrget = [shrstrd0, shrstrd1, &shrarr](int i, int j, int k) -> int{
return shrarr[i * shrstrd0 + j * shrstrd1 + k];
};
auto shrset = [shrstrd0, shrstrd1, &shrarr](int i, int j, int k, ubyte val) -> void {
shrarr[i * shrstrd0 + j * shrstrd1 + k] = val;
};
int in_x = threadIdx.x;
int in_y = threadIdx.y;
shrset(in_y, in_x, 0, arr[in_y * stride + in_x]);
arr[in_y * stride + in_x] = shrget(in_y, in_x, 0);
}
""",
(同上)
options=['-std=c++11'])
#Equivalent to identity<<<1, dim3(32, 32, 1)>>>(arr, 64);
identity = mod.get_function("identity")
identity(gp.zeros((64, 64), np.ubyte), np.int32(64), block=(32, 32, 1))
每次访问 2 个事务,共享重放开销 0.083。将 dim2
减少到 8 会使问题消失,我也不明白。
部分回答:我对共享内存库的工作方式存在根本性的误解(即,它们是 banks,每个大约有一千个字节库),所以没有意识到它们是循环的,所以过多的填充意味着 32 行元素最终可能会不止一次地使用每个 bank。
不过,据推测,这种冲突并不是每次都出现 - 相反,它出现了,哦,从数字来看,一个区块大约出现 85 次。
我会把它留在这里一天,希望得到更完整的解释,然后关闭并接受这个答案。