我似乎無法弄清楚影響內核性能的基本因素。我實現了兩個簡單的內核,一個加載兩個圖像並逐個像素地添加它們,另一個加載兩個圖像,並按位進行加載。現在,我對它們進行了模板化,以便內核可以拍攝8位和32位圖像,以及1,3或4通道圖像。CUDA中的性能
所以,起初我有兩個內核加載全局內存爲uchar3
和float3
,與uchar4
等我也不太清楚有關使用三元組,不過,由於合併一起,所以我想我給它分析運行。我認爲,由於操作與通道號無關,因此我可以像讀取圖像一樣,將圖像看作是三倍寬度的1通道圖像,而不是其實際的圖像。
實際上,uchar3
全球負荷很大,太多比uchar
負荷慢。我的努力得到了證明。但是,唉,這隻發生在算術內核上。按位與運算顯示了完全相反的結果!
現在,我知道我可以將圖像數據加載爲uint
s而不是uchar
s,用於位運算,它應該完美地處理合並。但讓我們假設我只是想學習和理解正在發生的事情。
讓我們忘記float3
s和float4
s等。我的問題是與uchar
版本的內核。所以,簡而言之,爲什麼uchar
負載有時比負載快,有時不是?
我正在使用GTX 470計算能力2.0。
PS。根據CUDA編程指南,邏輯操作和添加操作具有相同的吞吐量。 (我的內核實際上必須首先將uchar
s轉換爲uint
s,但這應該在兩個內核中發生。)所以執行長度應該與我收集的內容大致相同。
算術添加內核(uchar
版):
__global__ void add_8uc1(uchar* inputOne, uchar* inputTwo, uchar* output, unsigned int width, unsigned int height, unsigned int widthStep)
{
const int xCoordinateBase = blockIdx.x * IMAGE_X * IMAGE_MULTIPLIER + threadIdx.x;
const int yCoordinate = blockIdx.y * IMAGE_Y + threadIdx.y;
if (yCoordinate >= height)
return;
#pragma unroll IMAGE_MULTIPLIER
for (int i = 0; i < IMAGE_MULTIPLIER && xCoordinateBase + i * IMAGE_X < width; ++i)
{
// Load memory.
uchar* inputElementOne = (inputOne + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x));
uchar* inputElementTwo = (inputTwo + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x));
// Write output.
*(output + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x)) = inputElementOne[0] + inputElementTwo[0];
}
}
位與內核:
__global__ void and_8uc1(uchar* inputOne, uchar* inputTwo, uchar* output, unsigned int width, unsigned int height, unsigned int widthStep)
{
const int xCoordinateBase = blockIdx.x * IMAGE_X * IMAGE_MULTIPLIER + threadIdx.x;
const int yCoordinate = blockIdx.y * IMAGE_Y + threadIdx.y;
if (yCoordinate >= height)
return;
#pragma unroll IMAGE_MULTIPLIER
for (int i = 0; i < IMAGE_MULTIPLIER && xCoordinateBase + i * IMAGE_X < width; ++i)
{
// Load memory.
uchar* inputElementOne = (inputOne + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x));
uchar* inputElementTwo = (inputTwo + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x));
// Write output.
*(output + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x)) = inputElementOne[0] & inputElementTwo[0];
}
}
的uchar3
版本除了加載/存儲線如下內容相同:
// Load memory.
uchar3 inputElementOne = *reinterpret_cast<uchar3*>(inputOne + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x) * 3);
uchar3 inputElementTwo = *reinterpret_cast<uchar3*>(inputTwo + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x) * 3);
// Write output.
*reinterpret_cast<uchar3*>(output + yCoordinate * widthStep + (xCoordinateBase + i * IMAGE_X + threadIdx.x) * 3)
= make_uchar3(inputElementOne.x + inputElementTwo.x, inputElementOne.y + inputElementTwo.y, inputElementOne.z + inputElementTwo.z);
與AND內核類似。 (我不確定我完全記得內核,說實話...明天我會證實這一點)。
你能告訴我們你的內核嗎?對未知代碼進行推理很難。也許可以告訴我們執行時間是如何比較的(即內核對於一個版本或另一個版本需要相似的時間,這是更快的,...)。 – Grizzly
你能提出一個簡潔的問題嗎?你想知道爲什麼加載一堆'uchar'可能比加載一堆'uchar3'更快? CUDA 5中的分析器會發出通知,說明未合併的加載/存儲是否成問題,即使是最基本的分析類型也是如此。關於這2起案件的比例是什麼? –
負載是線性的並且完美地結合在一起,至少在uchar情況下。我無法粘貼內核,因爲我現在不在工作。我想知道爲什麼它有時更快,有時不是。 –