C++ 如何在CUDA内核中使用共享内存?
我有以下CUDA内核:C++ 如何在CUDA内核中使用共享内存?,c++,cuda,shared-memory,C++,Cuda,Shared Memory,我有以下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-
__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);
}
}
以下是更多细节(如果需要更多信息,请询问!):
strategies
是指向strategie
对象列表的指针,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;
对于您在评论中确认的(i=0;i),您希望对350万数据中的每一个应用20k(这个数字来自您之前的问题)策略,并检查20k x 350万结果
如果没有共享内存,您必须从全局内存中读取所有数据20k次或所有策略350万次
共享内存可以通过减少全局内存访问来加速您的程序。假设您每次可以将1k策略和1k数据读取到共享内存,检查1k x 1k结果,然后重复此操作,直到所有结果都被检查。通过这种方式,您可以将全局内存访问减少到所有数据的20倍和所有策略的3.5k倍。这种情况类似到向量向量或叉积。您可以找到一些参考代码以了解更多详细信息
但是,您的每个数据都很大(838-D向量),可能策略也很大。您可能无法在共享mem中缓存大量数据(根据设备类型,每个数据块仅约48k)。因此,情况变为类似矩阵乘法的情况。对于这一点,您可以从以下链接中的矩阵乘法代码中获得一些提示
正如您在评论中确认的,您希望对350万数据中的每一个应用20k(这个数字来自上一个问题)策略,并检查20k x 350万结果
如果没有共享内存,您必须从全局内存中读取所有数据20k次或所有策略350万次
共享内存可以通过减少全局内存访问来加速您的程序。假设您每次可以将1k策略和1k数据读取到共享内存,检查1k x 1k结果,然后重复此操作,直到所有结果都被检查。通过这种方式,您可以将全局内存访问减少到所有数据的20倍和所有策略的3.5k倍。这种情况类似到向量向量或叉积。您可以找到一些参考代码以了解更多详细信息
但是,您的每个数据都很大(838-D向量),可能策略也很大。您可能无法在共享mem中缓存大量数据(根据设备类型,每个数据块仅约48k)。因此,情况变为类似矩阵乘法的情况。对于这一点,您可以从以下链接中的矩阵乘法代码中获得一些提示
对于未来寻求类似答案的人,以下是我的内核函数的最终结果:
__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);
}
}
\uuuuuu全局\uuuuuu无效优化器\u回溯测试(双*数据、策略*策略、整数策略计数、双投资、双盈利){
__共享的u uuuuu双共享数据[838];
如果(螺纹IDX.x<838){
sharedData[threadIdx.x]=数据[threadIdx.x];
}
__同步线程();
//使用栅格跨步循环。
//参考:https://devblogs.nvidia.com/parallelforall/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/
对于(inti=blockIdx.x*blockDim.x+threadIdx.x;
i<策略计数;
i+=blockDim.x*gridDim.x)
{
策略[i].回溯测试(共享数据、投资、盈利能力);
}
}
请注意,我在应用程序中同时使用.cuh和.cu文件,并将其放在.cu文件中。还请注意,在编译对象文件时,我在Makefile中使用了--device-c
。我不知道是否应该这样做,但这对我来说很有用。对于未来寻求类似答案的人,以下是我的结论对于我的内核函数:
__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);
}
}
\uuuuuu全局\uuuuuu无效优化器\u回溯测试(双*数据、策略*策略、整数策略计数、双投资、双盈利){
__共享的u uuuuu双共享数据[838];
如果(螺纹IDX.x<838){
sharedData[threadIdx.x]=数据[threadIdx.x];
}
__同步线程();
//使用栅格跨步循环。
//参考:https://devblogs.nvidia.com/parallelforall/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/
对于(inti=blockIdx.x*blockDim.x+threadIdx.x;
i<策略计数;
i+=blockDim.x*gridDim.x)
{
策略[i].回溯测试(共享数据、投资、盈利能力);
}
}
请注意,我在应用程序中同时使用.cuh和.cu文件,并将其放在.cu文件中。还请注意,在编译对象文件时,我在Makefile中使用了--device-c
。我不知道是否应该这样做,但这对我来说是有效的。为什么sharedData
是一个指针数组?现在还不清楚你是怎么做的u试图在这里做的不是指针数组,而是指向内存中数组的指针。正如我已经解释过的,它是一个平面结构:[87.6,85.4,88.2,86.1,84.1,86.5,86.7,85.9,86.7,86.5,86.2,86.1,…]
数据[1]
是85.4
。这正是Strategy::backtest()
使用data
:它通过索引访问项。data
初始化如下:double*data=(double*)malloc(dataPointCount*dataPropertyCount*sizeof(double))
我不知道还有什么要解释的。哦,我明白你的意思。共享数据
应该是\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
。我将更新此内容。谢谢。请不要因为一次输入错误就投票结束我的问题。你真的是说你不能编写代码将4个双值加载到共享内存数组中吗?你这样做到底有什么问题?我不投赞成票
__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);
}
}