Optimization CUDA块和网格大小效率

Optimization CUDA块和网格大小效率,optimization,cuda,gpgpu,Optimization,Cuda,Gpgpu,在cuda中处理动态大小数据集的建议方法是什么 这是一种“根据问题集设置块和网格大小”的情况,还是值得将块维度指定为因子2,并使用一些内核逻辑来处理溢出 我可以看出这对块维度可能很重要,但这对网格维度有多重要?据我所知,实际的硬件约束在块级别停止(即分配给SM的块具有设置数量的SP,因此可以处理特定的扭曲大小) 我读过柯克的《大规模并行处理器编程》,但它并没有真正涉及这一领域。我认为通常最好根据问题集设置块和网格大小,尤其是为了优化目的。让额外的线程什么都不做是没有意义的,而且会降低程序的性能。

在cuda中处理动态大小数据集的建议方法是什么

这是一种“根据问题集设置块和网格大小”的情况,还是值得将块维度指定为因子2,并使用一些内核逻辑来处理溢出

我可以看出这对块维度可能很重要,但这对网格维度有多重要?据我所知,实际的硬件约束在块级别停止(即分配给SM的块具有设置数量的SP,因此可以处理特定的扭曲大小)


我读过柯克的《大规模并行处理器编程》,但它并没有真正涉及这一领域。

我认为通常最好根据问题集设置块和网格大小,尤其是为了优化目的。让额外的线程什么都不做是没有意义的,而且会降低程序的性能。

通常是根据总工作量设置块大小以获得最佳性能,并设置网格大小。大多数内核在每个Mp中都有一个“最佳”扭曲点,在那里它们工作得最好,您应该进行一些基准测试/评测,以了解这一点。您可能仍然需要内核中的溢出逻辑,因为问题大小很少是块大小的整数倍

编辑: 给出一个简单内核的具体示例(在本例中,自定义BLAS级别1 dscal类型操作作为压缩对称带矩阵的Cholesky分解的一部分):

//融合平方根和dscal运算
__全球
void cdivkernel(常量int n,双精度*a)
{
__共享u uuu双ONDIAGV;
int imin=threadIdx.x+blockDim.x*blockIdx.x;
int istride=blockDim.x*gridDim.x;
if(threadIdx.x==0){
oneondiagv=rsqrt(a[0]);
}
__同步线程();
对于(inti=imin;i(n,a);
errchk(cudaPeekAtLastError());
}

也许这提供了一些关于如何设计一个“通用”方案来根据输入数据大小设置执行参数的提示。

好的,我想我们在这里讨论两个问题

1) 分配块大小(即线程数)的好方法 这通常取决于您处理的数据类型。你在处理向量吗?你在处理矩阵吗?建议的方法是将线程数保持为32的倍数。因此,在处理向量时,启动256 x 1、512 x 1块就可以了。和处理矩阵时的相似性,32 x 8,32 x 16

2) 分配网格大小(即块数)的好方法 这里有点棘手。仅仅启动10000个模块,因为我们可以,通常不是做事情的最佳方式。在硬件内外切换块的成本很高。需要考虑的两个问题是每个块使用的共享内存,以及可用的SPS总数,并求解最佳数。p>
您可以从中找到一个非常好的实现方法。但是,可能需要一段时间才能弄清楚代码内部发生了什么。

如果您有动态调整大小的数据集,那么在某些线程和块等待其他线程和块完成时,您可能会遇到一些延迟问题

这有一些很好的启发。一些一般要点:

选择每个网格的块

  • 每个网格的块数应大于等于多处理器的数量
  • 内核中越多地使用
    \uu syncthreads()
    ,块就越多(这样一个块可以运行,而另一个块可以等待同步)
选择每个块的线程

  • 经纱尺寸的倍数(即通常为32)

  • 通常,最好选择线程数,使每个块的最大线程数(基于硬件)是线程数的倍数。例如,如果最大线程数为768,则每个块使用256个线程往往比使用512个线程要好,因为一个块上可以同时运行多个线程


griddim区域有什么想法吗?没那么棒。在发布代码之前,我对代码进行了一些清理,并在过程中引入了块大小计算错误。现在已修复,但希望您无论如何都能理解…@talonmies,这很漂亮。我的一个疑问是关于这一点。“对于(int i=imin;i@Pavan:是的,这确实意味着某些块将比其他块完成得更早,“最后”块将有一些扭曲差异。但总体而言,我发现替代方法更好,比如在内核启动结束时有一个“一半”GPU块。保持内核块驻留有助于摊销“设置”"索引和平方根计算降低了它们对整体性能的影响。@Talonmes,我不是说你需要启动更多的块,只是工作可能会均匀地分布在块上。比如,如果你有n=1.5*步距,而不是让一半块退休,然后为其余的块执行另一步,你就不能ry将每个块的扭曲度降低一半,并将工作分散到所有块上。请提供一个想法,因为这是我通常的做法。这里的(您的代码)有些新,对于一些应用程序来说可能是一个好主意。我需要对其进行测试:)您部分是对的。有16个线程(半扭曲)而不是14个线程是有意义的,而不是一直到256个。帕万:你能指出这个计算在什么地方进行吗?@Ashwin:推力::细节::后端::cuda::细节::启动\u闭包包含了所有血淋淋的细节。
// Fused square root and dscal operation
__global__ 
void cdivkernel(const int n, double *a)
{
    __shared__ double oneondiagv;

    int imin = threadIdx.x + blockDim.x * blockIdx.x;
    int istride = blockDim.x * gridDim.x;

    if (threadIdx.x == 0) {
        oneondiagv = rsqrt( a[0] );
    }
    __syncthreads();

    for(int i=imin; i<n; i+=istride) {
        a[i] *= oneondiagv;
    }
}
// Fused the diagonal element root and dscal operation into
// a single "cdiv" operation
void fusedDscal(const int n, double *a)
{
    // The semibandwidth (column length) determines
    // how many warps are required per column of the 
    // matrix.
    const int warpSize = 32;
    const int maxGridSize = 112; // this is 8 blocks per MP for a Telsa C2050

    int warpCount = (n / warpSize) + (((n % warpSize) == 0) ? 0 : 1);
    int warpPerBlock = max(1, min(4, warpCount));

    // For the cdiv kernel, the block size is allowed to grow to
    // four warps per block, and the block count becomes the warp count over four
    // or the GPU "fill" whichever is smaller
    int threadCount = warpSize * warpPerBlock;
    int blockCount = min( maxGridSize, max(1, warpCount/warpPerBlock) );
    dim3 BlockDim = dim3(threadCount, 1, 1);
    dim3 GridDim  = dim3(blockCount, 1, 1);

    cdivkernel<<< GridDim,BlockDim >>>(n,a);
    errchk( cudaPeekAtLastError() );
}