[英]It's slower to calculate integral image using CUDA than CPU code
我正在使用CUDA實現積分圖像計算模塊,以提高性能。 但是它的速度比CPU模塊慢。 請讓我知道我做錯了。 隨后是cuda內核和主機代碼。 而且,另一個問題是...在內核SumH中,使用紋理內存比全局內存慢,imageTexture的定義如下。
texture<unsigned char, 1> imageTexture;
cudaBindTexture(0, imageTexture, pbImage);
//內核水平和垂直掃描圖像。
__global__ void SumH(unsigned char* pbImage, int* pnIntImage, __int64* pn64SqrIntImage, float rVSpan, int nWidth)
{
int nStartY, nEndY, nIdx;
if (!threadIdx.x)
{
nStartY = 1;
}
else
nStartY = (int)(threadIdx.x * rVSpan);
nEndY = (int)((threadIdx.x + 1) * rVSpan);
for (int i = nStartY; i < nEndY; i ++)
{
for (int j = 1; j < nWidth; j ++)
{
nIdx = i * nWidth + j;
pnIntImage[nIdx] = pnIntImage[nIdx - 1] + pbImage[nIdx - nWidth - i];
pn64SqrIntImage[nIdx] = pn64SqrIntImage[nIdx - 1] + pbImage[nIdx - nWidth - i] * pbImage[nIdx - nWidth - i];
//pnIntImage[nIdx] = pnIntImage[nIdx - 1] + tex1Dfetch(imageTexture, nIdx - nWidth - i);
//pn64SqrIntImage[nIdx] = pn64SqrIntImage[nIdx - 1] + tex1Dfetch(imageTexture, nIdx - nWidth - i) * tex1Dfetch(imageTexture, nIdx - nWidth - i);
}
}
}
__global__ void SumV(unsigned char* pbImage, int* pnIntImage, __int64* pn64SqrIntImage, float rHSpan, int nHeight, int nWidth)
{
int nStartX, nEndX, nIdx;
if (!threadIdx.x)
{
nStartX = 1;
}
else
nStartX = (int)(threadIdx.x * rHSpan);
nEndX = (int)((threadIdx.x + 1) * rHSpan);
for (int i = 1; i < nHeight; i ++)
{
for (int j = nStartX; j < nEndX; j ++)
{
nIdx = i * nWidth + j;
pnIntImage[nIdx] = pnIntImage[nIdx - nWidth] + pnIntImage[nIdx];
pn64SqrIntImage[nIdx] = pn64SqrIntImage[nIdx - nWidth] + pn64SqrIntImage[nIdx];
}
}
}
//主機代碼
int nW = image_width;
int nH = image_height;
unsigned char* pbImage;
int* pnIntImage;
__int64* pn64SqrIntImage;
cudaMallocManaged(&pbImage, nH * nW);
// assign image gray values to pbimage
cudaMallocManaged(&pnIntImage, sizeof(int) * (nH + 1) * (nW + 1));
cudaMallocManaged(&pn64SqrIntImage, sizeof(__int64) * (nH + 1) * (nW + 1));
float rHSpan, rVSpan;
int nHThreadNum, nVThreadNum;
if (nW + 1 <= 1024)
{
rHSpan = 1;
nVThreadNum = nW + 1;
}
else
{
rHSpan = (float)(nW + 1) / 1024;
nVThreadNum = 1024;
}
if (nH + 1 <= 1024)
{
rVSpan = 1;
nHThreadNum = nH + 1;
}
else
{
rVSpan = (float)(nH + 1) / 1024;
nHThreadNum = 1024;
}
SumH<<<1, nHThreadNum>>>(pbImage, pnIntImage, pn64SqrIntImage, rVSpan, nW + 1);
cudaDeviceSynchronize();
SumV<<<1, nVThreadNum>>>(pbImage, pnIntImage, pn64SqrIntImage, rHSpan, nH + 1, nW + 1);
cudaDeviceSynchronize();
關於當前問題中的代碼。 我想提兩件事:啟動參數和計時方法。
啟動內核時,有兩個主要參數指定正在啟動的線程數量。 這些位於<<<
和>>>
部分之間,是網格中的塊數,以及每個塊的線程數,如下所示:
foo <<< numBlocks, numThreadsPerBlock >>> (args);
為了使單個內核在當前GPU上高效運行,可以使用經驗法則,即numBlocks * numThreadsPerBlock應該至少為10,000。 IE瀏覽器。 10,000件作品。 這是一條經驗法則,因此僅使用5,000個線程即可獲得良好的結果(隨GPU的不同而不同:便宜的GPU可以使用較少的線程擺脫故障),但這是您需要至少查看的數量級。 您正在運行1024個線程。 幾乎可以肯定這還不夠(提示:內核內部的循環看起來像掃描基元,可以並行完成)。
除此之外,還需要考慮其他一些事項。
我不會在這里深入探討,但是請確保您的時機合理。 GPU代碼傾向於具有一次性的初始化延遲。 如果這在您的時間范圍內,您將看到用於表示更大代碼的代碼的錯誤運行時。 同樣,CPU和GPU之間的數據傳輸也需要時間。 在實際的應用程序中,您只能對數千個內核調用執行一次此操作,但是在測試應用程序中,您可以在每次內核啟動時執行一次。
如果要獲得准確的計時,則必須使示例更能代表最終代碼,或者必須確保僅計時要重復的區域。
使用CUDA時,請注意以下幾點。
上面提到的GTX750具有512個CUDA內核(與着色器單元相同,只是以/ different /模式驅動)。 http://www.nvidia.de/object/geforce-gtx-750-de.html#pdpContent=2
創建積分圖像的職責只能部分並行化,因為結果數組中的任何結果值都取決於更大的前身。 此外,每次內存傳輸僅占很小的數學部分,因此ALU的功能強大,因此不可避免的內存傳輸可能成為瓶頸。 這樣的加速器可能會提供一些加速,但由於任務本身不允許這樣做,所以不能提供令人興奮的加速。
如果您要在相同的輸入數據上計算積分圖像的多個變化,則由於並行度選項和數學運算量的增加,您將更有可能看到“刺激”。 但這將是另一項職責。
作為來自Google搜索的一個瘋狂猜測-其他人已經擺弄了那些東西: https : //www.google.de/url? sa = t&rct = j&q =& esrc = s&source = web&cd =11& cad = rja&uact =8& ved = 0CD8QFjAKahUKUKEwjjnoabw8bIAhXFvhQKHb =A% 3A%2F%2Fdspace.mit.edu%2Fopenaccess-為散發%2F1721.1%2F71883&USG = AFQjCNHBbOEB_OHAzLZI9__lXO_7FPqdqA
確保的唯一方法是分析代碼,但是在這種情況下,我們可能可以做出合理的猜測。
基本上,您只是對某些數據進行一次掃描,並且對每個項目進行的處理極少。
考慮到您對每個項目進行的處理很少,使用CPU處理數據的瓶頸可能只是從內存中讀取數據。
在GPU上進行處理時,仍然需要從內存中讀取數據並將其復制到GPU的內存中。 這意味着我們仍然必須從主內存中讀取所有數據,就像CPU進行了處理一樣。 更糟糕的是,所有這些都必須寫入GPU的內存中,從而進一步降低速度。 到GPU甚至開始進行實際處理時,您已經比CPU完成工作所需的時間更多。
為了使Cuda有意義,您通常需要對每個單獨的數據項進行更多處理。 在這種情況下,CPU可能大部分時間已經幾乎處於空閑狀態,正在等待內存中的數據。 在這種情況下, 除非輸入數據已經存在於GPU的內存中, 否則 GPU不太會有幫助,因此GPU可以進行處理而無需任何額外的復制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.