我正在尝试理解以下代码的执行
template < class OP , ScanKind Kind , class T >
__device__ T scan_warp ( volatile T * ptr , const unsigned int idx = threadIdx.x )
{
const unsigned int lane = idx & 31; // index of thread in warp (0..31)
/*1*/if ( lane >= 1) ptr [ idx ] = OP :: apply ( ptr [ idx - 1] , ptr [ idx ]);
/*2*/if ( lane >= 2) ptr [ idx ] = OP :: apply ( ptr [ idx - 2] , ptr [ idx ]);
/*3*/if ( lane >= 4) ptr [ idx ] = OP :: apply ( ptr [ idx - 4] , ptr [ idx ]);
/*4*/if ( lane >= 8) ptr [ idx ] = OP :: apply ( ptr [ idx - 8] , ptr [ idx ]);
/*5*/if ( lane >= 16) ptr [ idx ] = OP :: apply ( ptr [ idx - 16] , ptr [ idx ]);
/*6*/if( Kind == inclusive ) return ptr [ idx ];
else return ( lane >0) ? ptr [ idx -1] : OP :: identity ();
}
通过写一个例子。
示例:
输入:[ 3 4 5 2 1 7 8 9 ]
正确输出: [ 3 7 12 14 15 22 30 39 ]
threadIdx.x = 0
,lane = 0
,输出:[ 3 4 5 2 1 7 8 9 ]
,(无if
语句执行)< / LI>
threadIdx.x = 1
,lane = 1
,输出:[ 3 7 5 2 1 7 8 9 ]
,(/ * 1 * /已执行)threadIdx.x = 2
,lane = 2
, outputTemp :[ 3 7 12 2 1 7 8 9 ]
,((/ * 1 * /已执行)), outputFinal :[ 3 7 15 2 1 7 8 9 ]
,(/ * 2 * /已执行)在 step3 中,outputTemp
通过应用第一个output
语句从 step2 中的if
获取。 outputFinal
是通过在if
中应用第二个outputTemp
语句获得的。所以在最终输出的第三个元素中有一个错误。而不是12我们有15。
问题:
const unsigned int lane = idx & 31;
检查if
语句中的条件,而不是idx
自己的条件。我的意思是,如果idx = [0 1...31]
lane
也是[0 1 2...31]
。 非常感谢你的时间。
答案 0 :(得分:2)
您显示的代码是 warp 扫描操作,这意味着它是由给定warp中的所有32个线程同时执行的。假设OP::apply
是一个加法运算,这意味着下面的中间值序列
输入[3 4 5 2 1 7 8 9]
步骤1 [3 7 9 7 3 8 15 17]车道1,2,3,4,5,6,7执行OP::apply( ptr[idx-1], ptr[idx])
步骤2 [3 7 12 14 12 15 18 25]车道2,3,4,5,6,7执行OP::apply( ptr[idx-2], ptr[idx])
步骤3 [3 7 12 14 15 22 30 39]车道4,5,6,7执行OP::apply( ptr[idx-4], ptr[idx])
另请注意,此代码预计会有32个输入值,因此尝试在您提供的示例上运行它会产生运行时错误。
因为典型的块包含超过32个线程(即多于1个warp),并且认为该代码可用于块中的任何warp。因此,threadIdx.x = 0..31
的相同计算也可用于threadIdx.x = 128..159
或threadIdx.x = 992..1023
可能,但笔和纸是一个更好的工具。