CUDA中重叠内核执行和数据传输的最佳数据大小
我有一个cuda内核,它将一个方阵的元素平方,它的工作非常有趣。我想使用3个cuda流,并将输入矩阵划分为多个块,以便以循环方式对给定块执行H2D MemcpyAsync、内核启动和D2H MemcpyAsync。下面是完整的源代码CUDA中重叠内核执行和数据传输的最佳数据大小,cuda,parallel-processing,Cuda,Parallel Processing,我有一个cuda内核,它将一个方阵的元素平方,它的工作非常有趣。我想使用3个cuda流,并将输入矩阵划分为多个块,以便以循环方式对给定块执行H2D MemcpyAsync、内核启动和D2H MemcpyAsync。下面是完整的源代码 #include<iostream> #include<vector> #include<cuda.h> #include<sys/time.h> using namespace std; __global__ voi
#include<iostream>
#include<vector>
#include<cuda.h>
#include<sys/time.h>
using namespace std;
__global__ void MatrixSquareKernel(int *inMatrix, int *outMatrix, size_t width, size_t rowCount) {
int myId = blockIdx.x * blockDim.x + threadIdx.x;
size_t crntRow = 0;
if(myId < width) {
size_t mId;
while(crntRow < rowCount) {
mId = myId * width + crntRow;enter code here
outMatrix[mId] = inMatrix[mId] * inMatrix[mId];
crntRow++;
}
}
}
int main() {
size_t count = width * width;
size_t size = count * sizeof(int);
vector<cudaStream_t> streams(strCount);
for(int i = 0; i < strCount; i++)
cudaStreamCreate(&streams[i]);
int *h_inMatrix, *h_outMatrix;
int *d_inMatrix, *d_outMatrix;
cudaHostAlloc((void **)&h_inMatrix, size, cudaHostAllocDefault);
cudaHostAlloc((void **)&h_outMatrix, size, cudaHostAllocDefault);
cudaMalloc((void **)&d_inMatrix, size);
cudaMalloc((void **)&d_outMatrix, size);
for(int i = 0; i = count; i++)
h_inMatrix[i] = i;
size_t optimalRows = 16;
size_t iter = width/optimalRows + ((width % optimalRows == 0)? 0: 1);
size_t chnkOffset, chnkSize, strId, sentRows;
struct timeval start, stop;
gettimeofday(&start, NULL);
for(int i = 0; i < iter; i++){
sentRows = i * optimalRows;
chnkOffset = width * sentRows;
chnkSize = width * optimalRows * sizeof(int);
if(sentRows > width){
optimalRows -= sentRows - width; //Cutoff the extra rows in this chunk if it's larger than the remaining unsent rows
chnkSize = width * optimalRows * sizeof(int);
}
strId = i % strCount;
cudaMemcpyAsync(d_inMatrix + chnkOffset, h_inMatrix + chnkOffset, chnkSize, cudaMemcpyHostToDevice, streams.at(strId));
MatrixSquareKernel<<<1, width, 0, streams.at(strId)>>>(d_inMatrix + chnkOffset, d_outMatrix + chnkOffset, width, optimalRows);
cudaMemcpyAsync(h_outMatrix + chnkOffset, d_outMatrix + chnkOffset, chnkSize, cudaMemcpyDeviceToHost, streams.at(strId));
}
cudaThreadSynchronize();
gettimeofday(&stop, NULL);
double elapsedTime = (stop.tv_sec - start.tv_sec) + (start.tv_usec - stop.tv_usec)/1e6;
cout<<"Elapsed Time: "<<elapsedTime<<endl;
for(int i = 0; i < strCount; i++)
cudaStreamDestroy(streams[i]);
cudaFreeHost(h_inMatrix);
cudaFreeHost(h_outMatrix);
cudaFree(d_inMatrix);
cudaFree(d_outMatrix);
return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
__全局无效矩阵squarekernel(int*inMatrix,int*outMatrix,size\t width,size\t rowCount){
int myId=blockIdx.x*blockDim.x+threadIdx.x;
尺寸=0;
如果(myId<宽度){
中等大小;
while(crntRow宽度){
optimalRows-=sentRows-width;//如果此块中的多余行大于剩余的未发送行,则将其截断
chnkSize=宽度*行数*大小(整数);
}
strId=i%strCount;
cudaMemcpyAsync(d_inMatrix+chnkofset,h_inMatrix+chnkofset,chnkSize,cudaMemcpyHostToDevice,streams.at(strId));
矩阵quarekernel(d_inMatrix+chnkofset,d_outMatrix+chnkofset,width,optimizerows);
cudaMemcpyAsync(h_outMatrix+chnkofset,d_outMatrix+chnkofset,chnkSize,cudaMemcpyDeviceToHost,streams.at(strId));
}
cudaThreadSynchronize();
gettimeofday(&stop,NULL);
双延时=(stop.tv_sec-start.tv_sec)+(start.tv_usec-stop.tv_usec)/1e6;
库特
我想在给定这些参数的情况下,解上面的方程
会给我一个大于1的n值,但它会给我
小于1的值
您不是在最小化T\u tr
,您只是在寻找满足涉及T\u tr
的条件的n
小于1的值是有意义的。值为零是一个明显的解决方案,它可以为您提供
T_tr(0) = T_k-overhead // always true
另外,T_k-开销=2*T_k1-T_k2
是正确的
N * size(T_k) == N * T_tr(T_k) // considering the problem perfectly linear
由于您的问题是线性的,因此当您的GPU利用率最大时,该条件为真
这实际上是您首先应该做的:
最大化GPU利用率
重叠转让和执行
为了最大限度地提高利用率,您需要增加n
,直到执行线性增加。您还需要通过改进内存模式来优化内核:
不要对每个内核线程处理rowCount
,并在内存访问上有一个跨步,而应该对每个线程使用一个矩阵元素与每个扭曲的连续内存访问进行平方运算。
这也会简化内核,并且通常会增加gpu的使用(例如,每个扭曲使用更少的寄存器)
对于重叠执行和传输,您已经知道如何使用异步调用+流我不能最小化t\u tr
,它只是数据大小的函数,t\u tr(M)=Mbytes/BW
。原则上,t\u tr(0)
是未定义的,不等于tk-overhead
。此外,我不太明白你是如何得出这个N*size(tk)==N*tk tr(tk)
,tk(tk)的
没有任何意义。在处理时,rowCount
不是每个内核线程处理的,而是一行中的每个元素都由一个唯一的线程处理;因此,对于rowcountxn
矩阵,内核将以N个线程启动,其中threadi
处理colu中的rowCount
元素mni
。很抱歉,我使用的术语与您的略有不同。在我的回答中T\u tr(x)
是处理问题x
和最小化T\u tr(x)所需的时间
是主要目标。我的答案基于您可以在大多数GPU上观察到的一种行为:如果您的GPU具有1000 ALU,则处理1000个元素的时间应与处理单个元素的时间大致相同。此外,由于流水线、无序执行、缓存……处理100K元素的速度只能比处理单个元素的速度稍慢元素(速度不是100K)。因此,请确保在分割执行时GPU已被充分利用