cuda乘法

cuda乘法,cuda,multiplication,Cuda,Multiplication,串行代码段如下所示: int i, j; for(j=0; j<ny; j++) { for(i=0; i<nx; i++) { x[i + j*nx] *= y[i]; } } 我使用以下内核将其转换为CUDA: int tid = blockIdx.x * blockDim.x + threadIdx.x; int i,j; for(tid = 0; tid <nx*ny; tid++) { j = tid/nx;

串行代码段如下所示:

int i, j;
for(j=0; j<ny; j++)
{
    for(i=0; i<nx; i++)
    {
        x[i + j*nx] *= y[i];
    }
}
我使用以下内核将其转换为CUDA:

int tid = blockIdx.x * blockDim.x + threadIdx.x;
int i,j;
for(tid = 0; tid <nx*ny; tid++)
{
    j = tid/nx;
    i = tid - j*nx;
    x[tid] *= y[i];
}

然而,GPU内核没有提供任何加速改进?有没有更好的解决方案的建议??提前谢谢

这个街区有多大?可能是将少量数据复制到GPU和设置环境所需的时间比计算时间长得多


还要记住,CUDA在第一次运行时会进行jit编译,因此为了获得准确的基准测试,您需要多次运行它。

如果这是串行代码:

  int i, j;
  for(j=0; j<ny; j++)
  {
      for(i=0; i<nx; i++)
      {
          x[i + j*nx] *= y[i];
      }
  }
那么你应该这样做:

  __global__ void fn(float *x, int nx)
  {
     int tid = blockIdx.x * blockDim.x + threadIdx.x;
     int j = tid/nx, i = tid - j * nx;
     x[tid] *= y[i];
  }

  fn<<<nx*ny/B, B>>>(x, nx); // with B = 256, 512, etc.
您所做的事情相当奇怪:您指示CUDA内核的每个线程迭代0到nx*ny之间的所有tid值,并计算与您的CPU版本相同的函数!此外,与CPU版本相比,您实际上执行循环的效率更低,而不仅仅是迭代索引;换句话说,您在每个线程中做相同的事情,只是效率比在CPU上的一个线程中低。难怪这会更慢;它应该慢得多。您的CUDA内核是:

  int **tid** = blockIdx.x * blockDim.x + threadIdx.x;
  int i,j;
  for(**tid** = 0; **tid** <nx*ny; **tid**++)
  {
      j = tid/nx;
      i = tid - j*nx;
      x[tid] *= y[i];
  }
这会对每个线程进行nx*ny迭代,与主机代码相同;您将失去并行性的所有好处,因为每个线程都在做相同的事情;使用GPU上的一个线程,您将获得相同的性能,并且得到相同的结果


如果这是CUDA源文件中的逐字代码,则需要对其进行更改并重新进行比较;如果这是您编写的代码,以帮助解释您的代码为非CUDA受众所做的工作,那么您需要展示您的实际CUDA代码,以便我们可以看到正在发生的事情。。。事实上,我所做的性能分析——一个微不足道的分析——是您所能期待的。

使用共享内存尝试一下。最佳实施方案之一:

// Matrices are stored in row-major order:
// M(row, col) = *(M.elements + row * M.stride + col)
typedef struct {
   int width;
   int height;
   int stride; // In number of elements
   float *elements;
} Matrix;

// Thread block size
#define BLOCK_SIZE 16

// Get a matrix element
__device__ float GetElement(const Matrix A, int row, int col)
{
   return A.elements[row * A.stride + col];
}

// Set a matrix element
__device__ void SetElement(Matrix A, int row, int col, float value)
{
   A.elements[row * A.stride + col] = value;
}
// Get the BLOCK_SIZExBLOCK_SIZE sub-matrix Asub of A that is
// located col sub-matrices to the right and row sub-matrices down
// from the upper-left corner of A
__device__ Matrix GetSubMatrix(Matrix A, int row, int col)
{
   Matrix Asub;
   Asub.width = BLOCK_SIZE; Asub.height = BLOCK_SIZE;
   Asub.stride = A.stride;
   Asub.elements = &A.elements[A.stride * BLOCK_SIZE * row + 
                               BLOCK_SIZE * col];
   return Asub;
}

// Forward declaration of the matrix multiplication kernel
__global__ void MatMulKernel(const Matrix, const Matrix, Matrix);

// Matrix multiplication - Host code
// Matrix dimensions are assumed to be multiples of BLOCK_SIZE
void MatMul(const Matrix A, const Matrix B, Matrix C)
{
   // Same as in previous example, except the followings:
   // d_A.width = d_A.stride = A.width;
   // d_B.width = d_B.stride = B.width;
   // d_C.width = d_C.stride = C.width;
}
// Matrix multiplication kernel called by MatMul()
__global__ void MatMulKernel(Matrix A, Matrix B, Matrix C)
{
   // Block row and column
   int blockRow = blockIdx.y;
   int blockCol = blockIdx.x;

   // Each thread block computes one sub-matrix Csub of C
   Matrix Csub = GetSubMatrix(C, blockRow, blockCol);

   // Each thread computes one element of Csub
   // by accumulating results into Cvalue
   float Cvalue = 0;

   // Thread row and column within Csub
   int row = threadIdx.y;
   int col = threadIdx.x;
// Loop over all the sub-matrices of A and B that are
   // required to compute Csub
   // Multiply each pair of sub-matrices together
   // and accumulate the results
   for (int m = 0; m < (A.width / BLOCK_SIZE); ++m) 
   {
      // Get sub-matrix Asub of A and Bsub of B
      Matrix Asub = GetSubMatrix(A, blockRow, m);
      Matrix Bsub = GetSubMatrix(B, m, blockCol);

      // Shared memory used to store Asub and Bsub respectively
      __shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
      __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];

      // Load Asub and Bsub from device memory to shared memory
      // Each thread loads one element of each sub-matrix
      As[row][col] = GetElement(Asub, row, col);
      Bs[row][col] = GetElement(Bsub, row, col);

      // Synchronize to make sure the sub-matrices are loaded
      // before starting the computation
      __syncthreads();
      // Multiply Asub and Bsub together
      for (int e = 0; e < BLOCK_SIZE; ++e)
         Cvalue += As[row][e] * Bs[e][col];

      // Synchronize to make sure that the preceding
      // computation is done before loading two new
      // sub-matrices of A and B in the next iteration
      __syncthreads();
   }

   // Write Csub to device memory
   // Each thread writes one element
   SetElement(Csub, row, col, Cvalue);
}
鉴于您对以下内容的评论:


nx*ny=2205;所以我用了块数= nx*ny+threads-1/线程和线程=64

这意味着您打算在每次计算中启动一个线程,正确的CUDA实现应该是:

int tid = blockIdx.x * blockDim.x + threadIdx.x;
int j = tid/nx;
int i = tid - j*nx;

if (tid < (nx*ny))
    x[tid] *= y[i];
如果您打算让每个线程在每次内核启动时计算多个计算,那么您将调整网格大小以填充目标GPU上的每个SM,而不是使用与输入大小相同的线程数,然后执行以下操作:

int tid = blockIdx.x * blockDim.x + threadIdx.x;
int gsize = blockDim.x * gridDim.x;
int i,j;

for(; tid <nx*ny; tid+=gsize)
{
    j = tid/nx;
    i = tid - j*nx;
    x[tid] *= y[i];
}

这将使您至少合并对x的读写,并删除发布版本中大量的冗余计算。可以进行一些进一步的优化,但这需要比问题和后续评论中提供的更多有关问题的信息。您的索引方案包含一个整数除法,然后每个计算包含一个整数乘加。对于每个输入值的单个触发器来说,这是一个很大的开销。然而,尽管如此,如果我引用的问题大小是您感兴趣的实际问题大小,那么GPU将永远不会比普通主机CPU更快。使用GPU进行这种低运算强度的运算时,要实现有效的加速,需要许多数量级的大问题。

i,j有多长?你们在网格中使用了多少块?你们的CUDA代码中有一个相当严重的打字错误。计算tid,然后扔掉计算值,让它假设值介于0和nx*ny之间。这几乎肯定不是你想做的。。。请看下面我的答案。这并不奇怪,因为内核是完全串行的。每根线都做同样的事情@维维科夫:请使用共享内存查看我的答案nx*ny=2205;因此,我使用了blocks=nx*ny+threads-1/threads and threads=64。这段代码不执行提问者询问的操作。当我运行一个包含2205个元素的小案例时,我在VisualProfiler中看到这个联合内核被调用。但是,对于一个大约有2000万个元素的非常大的例子,我看不到分析器中调用的内核。因此,我试图通过使用联合读访问方法,看看执行时间是否有改进,正如您在我的粗略实现中所描述的那样。有什么想法吗?我使用的是C2070 btw,我使用的是CUDA_SAFE_调用,以确保如果数据集未填充到GPU上,cudaMemcopy会给我一个错误。@vivekv80:编辑对您的实现的更全面的描述,最好是在原始问题中添加一个简洁的重新编写案例,可能有人能够查看它。这可以使用共享数据库来实现吗记忆??我真的不明白这样做有什么好处。但正如我在两个月前所说,如果您想要一个关于性能或优化的更具体的答案,请发布一些真实的代码。但实际上,您的主要问题似乎是继续缺乏对CUDA执行模型的理解。在担心性能或优化之前,我会先关注这一点。