C++ 如何在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-

我有以下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);
    }
}

以下是更多细节(如果需要更多信息,请询问!):

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);
    }
}