本文翻译自:http://goparallel.sourceforge.net/offload-your-code-to-your-gpu-how-to-get-started/
水平有限,还望各路大侠指点一二。
在写这篇文章的时候,大部分PC都已经有独立显卡了,而且还都是多核处理器,这些牛逼的显卡能够支持更高级的图形效果。但是,大部分时间,他们都处在空闲状态,直到有图形显示程序(译者:比如游戏)开起来,他们才起作用。过去,人们努力尝试使用显卡上的处理器核心的进展不大。但是,Intel的平行工作室(Parallel Studio)却让它变得简单,然后,我就打算在我以后的软件开发项目中使用这项技术。这篇博客向你展示了使用平行工作室的图形技术的基本方法。
简单的例子程序
在开始前,我们需要一个普通的程序来展示如何使用Intel的图形技术。为了让东西简单点,我创建了一个程序,用来把RGB值转成灰度值。
#define _NUMCOLORS 256*256*256
void RGBToGray(int &nRGB, int &nGray)
{
int nRed = nRGB >> 16;
int nGreen = (nRGB >> 8) & 0xff;
int nBlue = nRed & 0xff;
double dRedPortion = (double)nRed * 0.21;
double dGreenPortion = (double)nGreen * 0.72;
double dBluePortion = (double)nBlue * 0.07;
nGray = (int)dRedPortion + (int)dGreenPortion + (int)dBluePortion;
}
void CreateInBufferValues(int *InBuffer)
{
for (int i = 0; i < _NUMCOLORS; i++)
{
InBuffer[i] = i;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int *InBuffer = new int[_NUMCOLORS];
int *OutBuffer = new int[_NUMCOLORS];
CreateInBufferValues(InBuffer);
for (int i = 0; i < _NUMCOLORS; i++)
{
RGBToGray(InBuffer[i], OutBuffer[i]);
}
return 0;
}
清单1:用来探索用GPU编程的示例程序
我们可以用并行化for循环的方法来让这段程序优化很多。事实上,在我们把程序卸载到GPU之前,我们就是需要先并行化程序的。所以,清单2中所改的地方就是上述的优化项,并且为卸载到GPU上做准备。
for (int i = 0; i < _NUMCOLORS; i++)
{
RGBToGray(InBuffer[i], OutBuffer[i]);
}
改成
cilk_for(int i = 0; i < _NUMCOLORS; i++)
{
RGBToGray(InBuffer[i], OutBuffer[i]);
}
清单2:并行化代码,为放到GPU上所做的准备工作
同步卸载(offload)
卸载有2种类型。1种是同步,另一种是异步。同步中有2步,第一步是,被调用的函数必须用__declspec(target(gfx))修饰,第二步是必须在并行的for循环前加上#pragma offload。清单3展示了清:单1中的代码的改进版。
#define _NUMCOLORS 256*256*256
__declspec (target(gfx))
void RGBToGray(int &nRGB, int &nGray)
{
int nRed = nRGB >> 16;
int nGreen = (nRGB >> 8) & 0xff;
int nBlue = nRGB & 0xff;
double dRedPortion = (double)nRed * 0.21;
double dGreenPortion = (double)nGreen * 0.72;
double dBluePortion = (double)nBlue * 0.07;
nGray = (int)dRedPortion + (int)dGreenPortion + (int)dBluePortion;
}
void CreateInBufferValues(int *InBuffer)
{
for (int i = 0; i < _NUMCOLORS; i++)
{
InBuffer[i] = i;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int *InBuffer = new int[_NUMCOLORS];
int *OutBuffer = new int[_NUMCOLORS];
CreateInBufferValues(InBuffer);
#pragma offload target(gfx) pin(InBuffer, OutBuffer:length(_NUMCOLORS))
cilk_for(int i = 0; i < _NUMCOLORS; i++)
{
RGBToGray(InBuffer[i], OutBuffer[i]);
}
return 0;
}
清单
3:
清
单
1
中的代码的改进版
重新来看下同步卸载的步骤。首先,卸载的循环必须并行化,在例子中,这里用了cilk_for。第二,卸载的函数必须被__declspec(target(gfx))修饰。第三,并行化的for循环前必须加上卸载的pragma。
异步卸载(offload)
从软件开发的立场来说,同步和异步最大的不同就是,同步是一种基于pragma的方法,而异步是一种基于API的方法。
在开始前,我们需要写一个包含并行化for循环的函数,它是自己被卸载的。清单4显示了我们用作异步卸载的例子,在函数前,加了一句__declspec(target(gfx_kernel))
__declspec(target(gfx_kernel))
void offload(int *InBuffer, int *OutBuffer)
{
cilk_for(int i = 0; i < _NUMCOLORS; i++)
{
RGBToGray(InBuffer[i], OutBuffer[i]);
}
}
清单
4
:
将会被卸载的函数
第一个例子中的RGBToGray()函数一直都放在__declspec (target(gfx))之后。最后,清单5中的代码展示了所有异步卸载和执行所需要的东西。
__GFX_share(InBuffer, sizeof(int)*_NUMCOLORS);
__GFX_share(OutBuffer, sizeof(int)*_NUMCOLORS);
__GFX_enqueue("offload", InBuffer, OutBuffer);
__GFX_wait();
__GFX_unshare(InBuffer);
__GFX_unshare(OutBuffer);
清单5:卸载和执行的代码
总结
如你所见,在使用平行工作室(Parallel Studio)把代码卸载到GPU中,是很直接,很简单的。探索如何让你的程序表现的更好,真的是个很有挑战的技术活。
===============================================================================================================================================================
自言自语:
文中的几个概念
cilk_for:for的并行化版本,可以看http://blog.csdn.net/gengshenghong/article/details/7235125这篇文章,大神们早已探过路了
offload:转移,讲代码转移到GPU上运行
并行化:并行计算中的内容,详细可以搜mic编程
另外,关于这篇文章,其实我也没看懂多少,只是在翻译过程中大概搜了下上面的概念,所以翻译的肯定不一定正确,还望各位大侠们不吝赐教,跪谢~~~