在CUDA线程之间共享高度不规则的作业
我正在做一些与图遍历(维特比算法)相关的任务 每一步我都有一组压缩的活动状态,在每个状态下都会完成一些工作,然后结果会通过输出弧传播到每个弧的目标状态,从而构建新的活动状态集。 问题是输出弧的数量变化很大,从两个或三个到几千个不等。因此,计算线程的加载效率非常低 我尝试通过共享本地内存队列共享作业在CUDA线程之间共享高度不规则的作业,cuda,shared-memory,task-queue,graph-traversal,Cuda,Shared Memory,Task Queue,Graph Traversal,我正在做一些与图遍历(维特比算法)相关的任务 每一步我都有一组压缩的活动状态,在每个状态下都会完成一些工作,然后结果会通过输出弧传播到每个弧的目标状态,从而构建新的活动状态集。 问题是输出弧的数量变化很大,从两个或三个到几千个不等。因此,计算线程的加载效率非常低 我尝试通过共享本地内存队列共享作业 int tx = threaIdx.x; extern __shared__ int smem[]; int *stateSet_s = smem; //n
int tx = threaIdx.x;
extern __shared__ int smem[];
int *stateSet_s = smem; //new active set
int *arcSet_s = &(smem[Q_LEN]); //local shared queue
float *scores_s = (float*)&(smem[2*Q_LEN]);
__shared__ int arcCnt;
__shared__ int stateCnt;
if ( tx == 0 )
{
arcCnt = 0;
stateCnt = 0;
}
__syncthreads();
//load state index from compacted list of state indexes
int stateId = activeSetIn_g[gtx];
float srcCost = scores_g[ stateId ];
int startId = outputArcStartIds_g[stateId];
int nArcs = outputArcCounts_g[stateId]; //number of outgoing arcs to be propagated (2-3 to thousands)
/////////////////////////////////////////////
/// prepare arc set
/// !!!! that is the troubled code I think !!!!
/// bank conflicts? uncoalesced access?
int myPos = atomicAdd ( &arcCnt, nArcs );
while ( nArcs > 0 ) && ( myPos < Q_LEN ) )
{
scores_s[myPos] = srcCost;
arcSet_s[myPos] = startId + nArcs - 1;
myPos++;
nArcs--;
}
__syncthreads();
//////////////////////////////////////
/// parallel propagate arc set
if ( arcSet_s[tx] > 0 )
{
FstArc arc = arcs_g[ arcSet_s[tx] ];
float srcCost_ = scores_s[tx];
DoSomeJob ( &srcCost_ );
int *dst = &(transitionData_g[arc.dst]);
int old = atomicMax( dst, FloatToInt ( srcCost_ ) );
////////////////////////////////
//// new active set
if ( old == ILZERO )
{
int pos = atomicAdd ( &stateCnt, 1 );
stateSet_s[ pos ] = arc.dst;
}
}
/////////////////////////////////////////////
/// transfer new active set from smem to gmem
__syncthreads();
__shared__ int gPos;
if ( tx == 0 )
{
gPos = atomicAdd ( activeSetOutSz_g, stateCnt );
}
__syncthreads();
if ( tx < stateCnt )
{
activeSetOut_g[gPos + tx] = stateSet_s[tx];
}
__syncthreads();
inttx=threaIdx.x;
外部共享内部smem[];
int*stateSet_s=smem//新活动集
int*arcSet_s=&(smem[Q_LEN])//本地共享队列
浮动*分数=(浮动*)和(smem[2*Q_LEN]);
__共享_u u; int arcCnt;
__共享_u u; int状态;
如果(tx==0)
{
arcCnt=0;
stateCnt=0;
}
__同步线程();
//从压缩的状态索引列表加载状态索引
int stateId=activeSetIn_g[gtx];
浮动成本=分数[stateId];
int startId=outputArcStartIds_g[stateId];
int nArcs=输出计数[stateId]//要传播的传出弧数(2-3到数千)
/////////////////////////////////////////////
///准备弧集
/// !!!! 我想这就是问题代码!!!!
///银行冲突?未恢复访问?
int myPos=原子添加(&arcCnt,nArcs);
而(NACS>0)和(myPos0)
{
FstArc arc=arcs_g[arcSet_s[tx];
浮动成本=分数[tx];
DoSomeJob(&srcCost));
int*dst=&(传递数据[arc.dst]);
int old=atomicMax(dst,FloatToInt(srcCost)));
////////////////////////////////
////新活动集
if(old==ILZERO)
{
int pos=atomicAdd(&stateCnt,1);
状态集_s[pos]=arc.dst;
}
}
/////////////////////////////////////////////
///将新的活动集从smem传输到gmem
__同步线程();
__共享的_; int gpo;
如果(tx==0)
{
gPos=原子添加(activeSetOutSz_g,stateCnt);
}
__同步线程();
如果(tx
但它运行得非常慢,我的意思是,如果没有使用活动集(活动集=所有状态),则运行速度会慢一些,尽管活动集占所有状态的10–15%。注册压力大大增加,入住率很低,但我认为对此无能为力
线程之间是否有更有效的作业共享方式?
考虑一下3.0上的warp shuffle ops,但我必须使用2.x设备。通常,工作负载不均匀和动态工作创建的问题都是通过多次CUDA内核调用来解决的。这可以通过如下方式使CPU循环来实现:
//CPU pseudocode
while ( job not done) {
doYourComputationKernel();
loadBalanceKernel();
}
doYourComputationKernel()必须有一个启发式方法,以知道何时是停止并将控制发送回CPU以平衡工作负载的好时机。这可以通过使用空闲块数的全局计数器来完成。每当块完成其工作或无法创建更多工作时,此计数器将递增。当空闲块的数量超过阈值时,所有块中的工作都保存到全局内存中,并且所有块都完成
loadBalanceKernel()应接收包含所有已保存工作的全局数组以及每个块的另一个全局工作计数器数组。对后者进行reduce操作可以计算总的工作量。有了这个,可以找到每个区块的工程数量。最后,内核应该复制工作,以便每个块接收相同数量的元素
循环将继续,直到完成所有计算。有一篇关于这方面的好论文:。这个想法是为了平衡连续碰撞检测的负载,这是非常不均匀的。问题是什么?考虑原子总和<代码>原子添加> /代码>对应于实际的串行化操作。