如何在CUDA内核中使用共享内存
How can I use shared memory here in my CUDA kernel?
我有以下CUDA内核:
__global__ void optimizer_backtest(double *data, Strategy *strategies, int strategyCount, double investment, double profitability) {
// Use a grid-stride loop.
// Reference: https://devblogs.nvidia.com/parallelforall/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/
for (int i = blockIdx.x * blockDim.x + threadIdx.x;
i < strategyCount;
i += blockDim.x * gridDim.x)
{
strategies[i].backtest(data, investment, profitability);
}
}
TL;DR我想找到一种将data
存储在共享(__shared__
)内存中的方法。我不明白的是如何使用多个线程来填充共享变量。
我见过这样的例子,其中data
被逐个线程复制到共享内存(例如myblock[tid] = data[tid]
),但我不确定在我的情况下如何做到这一点。问题是,每个线程在数据集的每次迭代中都需要访问整个"行"(扁平化)数据(请参阅下面调用内核的位置)。
我希望有这样的东西:
__global__ void optimizer_backtest(double *data, Strategy *strategies, int strategyCount, int propertyCount, double investment, double profitability) {
__shared__ double sharedData[propertyCount];
// Use a grid-stride loop.
// Reference: https://devblogs.nvidia.com/parallelforall/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/
for (int i = blockIdx.x * blockDim.x + threadIdx.x;
i < strategyCount;
i += blockDim.x * gridDim.x)
{
strategies[i].backtest(sharedData, investment, profitability);
}
}
以下是更多详细信息(如果需要更多信息,请询问!):
strategies
是指向Strategy
对象列表的指针,而data
是指向已分配的扁平数据阵列的指针。
在backtest()
中,我访问这样的数据:
data[0]
data[1]
data[2]
...
无限制,数据是一个固定大小的2D阵列,类似于:
[87.6, 85.4, 88.2, 86.1]
84.1, 86.5, 86.7, 85.9
86.7, 86.5, 86.2, 86.1
...]
至于内核调用,我对数据项进行迭代,并对n个数据行(约350万)调用n次:
int dataCount = 3500000;
int propertyCount = 4;
for (i=0; i<dataCount; i++) {
unsigned int dataPointerOffset = i * propertyCount;
// Notice pointer arithmetic.
optimizer_backtest<<<32, 1024>>>(devData + dataPointerOffset, devStrategies, strategyCount, investment, profitability);
}
对于未来寻求类似答案的人来说,以下是我为内核函数所做的:
__global__ void optimizer_backtest(double *data, Strategy *strategies, int strategyCount, double investment, double profitability) {
__shared__ double sharedData[838];
if (threadIdx.x < 838) {
sharedData[threadIdx.x] = data[threadIdx.x];
}
__syncthreads();
// Use a grid-stride loop.
// Reference: https://devblogs.nvidia.com/parallelforall/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/
for (int i = blockIdx.x * blockDim.x + threadIdx.x;
i < strategyCount;
i += blockDim.x * gridDim.x)
{
strategies[i].backtest(sharedData, investment, profitability);
}
}
请注意,我在应用程序中同时使用.cuh和.cu文件,并将其放在.cu文件中。还要注意,在编译对象文件时,我在Makefile中使用--device-c
。我不知道事情是否应该这样做,但这对我来说是有效的。
正如您的评论中所确认的,您希望对每一个3.5米的数据应用20k(这个数字来自您上一个问题)策略,并检查20kx3.5米的结果。
如果没有共享内存,您必须从全局内存中读取2万次所有数据或350万次所有策略。
共享内存可以通过减少全局内存访问来加快程序的速度。假设你每次可以将1k策略和1k数据读取到共享内存中,检查1k x 1k的结果,然后重复此操作,直到全部检查完毕。通过这种方式,您可以将全局mem访问减少到所有数据的20倍和所有策略的3.5k倍。这种情况类似于向量向量的叉积。您可以找到一些参考代码来了解更多详细信息。
然而,你的每一个数据都很大(838-D矢量),也许策略也很大。您可能无法在共享内存中缓存大量内存(根据设备类型,每个块只能缓存~48k)。所以情况就变成了矩阵乘法。为此,您可能会从以下链接中的矩阵乘法代码中得到一些提示。
http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-存储器
- 使用Boost Interprocess创建托管共享内存需要很长时间
- 字符串共享内存映射的向量
- CUDA 使用共享内存平铺 3D 卷积实现
- 共享内存:MapViewOfFile 返回错误 5
- 如何在多写入器情况下对文件支持的共享内存中的大页面出错
- 有没有办法列出所有共享内存对象的名称?
- 共享内存的升压容器是否实现锁定?
- 共享内存中的健壮互斥锁不是那么健壮
- 使用IPC/共享内存将Integer数组从C++传递到Python
- 共享内存和性能
- 在这种特殊情况下,我是否需要在共享内存中使用原子类型
- 是否可以在专用内存空间中分配一个为提升管理共享内存而创建的对象
- fork(),在C中共享内存和指针
- 访问共享内存而不使用易失性、std::atomic、信号量、互斥锁和自旋锁
- 提升进程间共享内存open_or_create每次都会引发异常
- 通过 mmap-ed 共享内存传递可变长度 C 字符串
- 越界访问 CUDA 共享内存
- 在共享内存中插入映射映射时出现编译器错误
- 矩阵矢量产品 CUDA 通过平铺和共享内存提高性能
- 如何更改在 c++ 中使用提升库创建的共享内存的路径