我有一個簡單的掃描內核,它可以計算循環中幾個塊的掃描。我注意到,當get_local_id()存儲在局部變量中而不是在循環內調用時,性能有所提高。因此,爲了與代碼總結,這樣的:OpenCL的代價get_local_id()
__kernel void LocalScan_v0(__global const int *p_array, int n_array_size, __global int *p_scan)
{
const int n_group_offset = get_group_id(0) * SCAN_BLOCK_SIZE;
p_array += n_group_offset;
p_scan += n_group_offset;
// calculate group offset
const int li = get_local_id(0); // *** local id cached ***
const int gn = get_num_groups(0);
__local int p_workspace[SCAN_BLOCK_SIZE];
for(int i = n_group_offset; i < n_array_size; i += SCAN_BLOCK_SIZE * gn) {
LocalScan_SingleBlock(p_array, p_scan, p_workspace, li);
p_array += SCAN_BLOCK_SIZE * gn;
p_scan += SCAN_BLOCK_SIZE * gn;
}
// process all the blocks in the array (each block size SCAN_BLOCK_SIZE)
}
有吞吐量74 GB/s的GTX-780,而這一點:
__kernel void LocalScan_v0(__global const int *p_array, int n_array_size, __global int *p_scan)
{
const int n_group_offset = get_group_id(0) * SCAN_BLOCK_SIZE;
p_array += n_group_offset;
p_scan += n_group_offset;
// calculate group offset
const int gn = get_num_groups(0);
__local int p_workspace[SCAN_BLOCK_SIZE];
for(int i = n_group_offset; i < n_array_size; i += SCAN_BLOCK_SIZE * gn) {
LocalScan_SingleBlock(p_array, p_scan, p_workspace, get_local_id(0));
// *** local id polled inside the loop ***
p_array += SCAN_BLOCK_SIZE * gn;
p_scan += SCAN_BLOCK_SIZE * gn;
}
// process all the blocks in the array (each block size SCAN_BLOCK_SIZE)
}
在相同的硬件上只有70 GB /秒。唯一的區別是對get_local_id()的調用是在循環內部還是外部。 LocalScan_SingleBlock()中的代碼在this GPU Gems article中有很多描述。
現在,這帶來了一些問題。我一直認爲線程標識存儲在某個寄存器中,並且對任何線程局部變量的訪問速度都很快。這似乎並非如此。我總是習慣於把一個本地ID緩存在一個變量中,而這個變量不願意讓一個老的「C」程序員不願意在一個循環中調用一個函數,如果他希望每次都返回相同的值,不要認爲這會有所作爲。
任何想法,爲什麼這可能是?我沒有做任何檢查編譯的二進制代碼。有沒有人有相同的經歷? CUDA中的threadIdx.x
與此相同嗎? ATI平臺如何?這種行爲是在什麼地方描述的?我通過CUDA最佳實踐快速掃描,但沒有發現任何內容。
請不要刪除CUDA標記。雖然代碼本身不在CUDA中,但問題體現在NVIDIA硬件上,與CUDA的threadIdx的實現方式密切相關,以及它如何影響程序的runitme。 –