AMD OpenCL大学课程(12) 性能优化案例NBody

简介: 本节主要介绍NBody算法的OpenCL性能优化。 1、NBody     NBody系统主要用来通过粒子之间的物理作用力来模拟星系系统。每个粒子表示一个星星,多个粒子之间的相互作用,就呈现出星系的效果。

    本节主要介绍NBody算法的OpenCL性能优化。

1、NBody

    NBody系统主要用来通过粒子之间的物理作用力来模拟星系系统。每个粒子表示一个星星,多个粒子之间的相互作用,就呈现出星系的效果。

image

 

   上图为一个粒子模拟星系的图片:Source: THE GALAXY-CLUSTER-SUPERCLUSTER CONNECTIONhttp://www.casca.ca/ecass/issues/1997-DS/West/west-bil.html

   由于每个粒子之间都有相互作用的引力,所以这个算法的复杂度是N2的。下面我们主要探讨如何优化算法以及在OpenCL基础上优化算法。

2、NBody算法

   假设两个粒子之间通过万有引力相互作用,则任意两个粒子之间的相互作用力F公式如下:

image

   最笨的方法就是计算每个粒子和其它粒子的作用力之和,这个方法通常称作N-Pair的NBody模拟。

   粒子之间的万有引力和它们之间的距离成反比,对于一个粒子而言(假设粒子质量都一样),远距离粒子的作用力有时候很小,甚至可以忽略。Barnes Hut 把3D空间按八叉树进行分割,只有在相邻cell的粒子才直接计算它们之间的引力,远距离cell中的粒子当作一个整体来计算引力。

image

3、OpenCL优化Nbody

     在本节中,我们不考虑算法本身的优化,只是通过OpenCL机制来优化N-Pair的NBody模拟。

     最简单的实施方法就是每个例子的作用力相加,代码如下:

for(i=0; i<n; i++)
{
ax = ay = az = 0;
// Loop over all particles "j”
for (j=0; j<n; j++) {

//Calculate Displacement
dx=x[j]-x[i];
dy=y[j]-y[i];
dz=z[j]-z[i];

// small eps is delta added for dx,dy,dz = 0
invr= 1.0/sqrt(dx*dx+dy*dy+dz*dz +eps);
invr3 = invr*invr*invr;
f=m[ j ]*invr3;

// Accumulate acceleration
ax += f*dx;
ay += f*dy;
az += f*dx;
}
// Use ax, ay, az to update particle positions
}

我们对每个粒子计算作用在它上面的合力,然后求在合力作用下,delta时间内粒子的新位置,并把这个新位置当作下次计算的输入参数。

image

没有优化的OpenCL kernel代码如下:

__kernel void nbody_sim_notile(
__global float4* pos ,
__global float4* vel,
int numBodies,
float deltaTime,
float epsSqr,
__local float4* localPos,
__global float4* newPosition,
__global float4* newVelocity)

{
unsigned int tid = get_local_id(0);
unsigned int gid = get_global_id(0);
unsigned int localSize = get_local_size(0);

// position of this work-item
float4 myPos = pos[gid];
float4 acc = (float4)(0.0f, 0.0f, 0.0f, 0.0f);

// load one tile into local memory
int idx = tid * localSize + tid;
localPos[tid] = pos[idx];

// calculate acceleration effect due to each body
// a[i->j] = m[j] * r[i->j] / (r^2 + epsSqr)^(3/2)
for(int j = 0; j < numBodies; ++j)
{
// Calculate acceleartion caused by particle j on particle i
localPos[tid] = pos[j];
float4 r = localPos[j] - myPos;
float distSqr = r.x * r.x + r.y * r.y + r.z * r.z;
float invDist = 1.0f / sqrt(distSqr + epsSqr);
float invDistCube = invDist * invDist * invDist;
float s = localPos[j].w * invDistCube;

// accumulate effect of all particles
acc += s * r;
}

float4 oldVel = vel[gid];

// updated position and velocity
float4 newPos = myPos + oldVel * deltaTime + acc * 0.5f * deltaTime * deltaTime;
newPos.w = myPos.w;

float4 newVel = oldVel + acc * deltaTime;

// write to global memory
newPosition[gid] = newPos;
newVelocity[gid] = newVel;
}

在这种实现中,每次都要从global memory中读取其它粒子的位置,速度,内存访问= N reads*N threads= N2

我们可以通过local memory进行优化,一个粒子数据读进来以后,可以被p*p个线程共用,p*p即为workgroup的大小,对于每个粒子,我们通过迭代p*p的tile,累积得到最终结果。

image

优化后的kernel代码如下:

__kernel void nbody_sim(

__global float4* pos ,

__global float4* vel,

int numBodies,

float deltaTime,

float epsSqr,

__local float4* localPos,
__global float4* newPosition,
__global float4* newVelocity)

{
unsigned int tid = get_local_id(0);

unsigned int gid = get_global_id(0);

unsigned int localSize = get_local_size(0);


// Number of tiles we need to iterate

unsigned int numTiles = numBodies / localSize;

// position of this work-item

float4 myPos = pos[gid];

float4 acc = (float4)(0.0f, 0.0f, 0.0f, 0.0f);

for(int i = 0; i < numTiles; ++i)

{

// load one tile into local memory

int idx = i * localSize + tid;

localPos[tid] = pos[idx];



// Synchronize to make sure data is available for processing

barrier(CLK_LOCAL_MEM_FENCE);

// calculate acceleration effect due to each body

// a[i->j] = m[j] * r[i->j] / (r^2 + epsSqr)^(3/2)

for(int j = 0; j < localSize; ++j)

{

// Calculate acceleartion caused by particle j on particle i

float4 r = localPos[j] - myPos;

float distSqr = r.x * r.x + r.y * r.y + r.z * r.z;

float invDist = 1.0f / sqrt(distSqr + epsSqr);

float invDistCube = invDist * invDist * invDist;

float s = localPos[j].w * invDistCube;

// accumulate effect of all particles

acc += s * r;

}

// Synchronize so that next tile can be loaded

barrier(CLK_LOCAL_MEM_FENCE);

}

float4 oldVel = vel[gid];

// updated position and velocity

float4 newPos = myPos + oldVel * deltaTime + acc * 0.5f * deltaTime * deltaTime;

newPos.w = myPos.w;

float4 newVel = oldVel + acc * deltaTime;

// write to global memory

newPosition[gid] = newPos;

newVelocity[gid] = newVel;
}

下面是在AMD, NV两个平台上性能测试结果:

AMD GPU = 5870 Stream SDK 2.2

Nvidia GPU = GTX 480 with CUDA 3.1

image

另外,在程序中,也尝试了循环展开,通过展开内循环,从而减少GPU执行分支指令,我的测试中,使用展开四次,得到的FPS比没展开前快了30%。(AMD 5670显卡)。具体实现可以看kernel代码中的__kernel void nbody_sim_unroll函数。在AMD平台上,使用向量化也可以提高10%左右的性能。

最后提供2篇NBody优化的文章:

—Nvidia GPU Gems

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch31.html

—Brown Deer Technology

http://www.browndeertechnology.com/docs/BDT_OpenCL_Tutorial_NBody.html

完整的代码可从:http://code.google.com/p/imagefilter-opencl/downloads/detail?name=amduniCourseCode7.zip&can=2&q=#makechanges 下载。

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
相关文章
|
3月前
|
存储 JSON API
Python轻松玩转JSON文件:读写实战指南
Python轻松玩转JSON文件:读写实战指南
285 22
|
前端开发 API 网络架构
深入浅出:GraphQL 的优势与使用场景
【10月更文挑战第6天】深入浅出:GraphQL 的优势与使用场景
1484 0
|
4月前
|
人工智能 监控 数据可视化
2025 主流 BI 工具全景盘点——10款国内外产品赋能企业决策
2025年BI工具迎来AI驱动新阶段,市场规模持续扩张。本文盘点10款主流产品,涵盖瓴羊Quick BI、Power BI、Tableau等,聚焦AI交互、行业适配与生态集成三大趋势,解析各工具核心技术与场景价值,助力企业精准选型,赋能数字化决策升级。Quick BI(阿里云旗下)核心优势:国内唯一连续 6 年入选 Gartner ABI 魔力象限的智能 BI 产品;搭载智能小Q多Agent协同分析功能,中文语义识别准确率达 98%。
|
Ubuntu Linux 应用服务中间件
Linux使用cpulimit对CPU使用率进行限制
cpulimit是一款简单易用的CPU使用率限制工具,支持对特定程序或整个CPU使用率进行限制。可通过源安装(如`yum`或`apt-get`)或编译安装获取。使用时,可针对程序名、进程号或绝对路径设置CPU占用上限(如`cpulimit -e xmrig -l 60 -b`)。ROOT用户可限制所有进程,普通用户仅限于权限范围内进程。注意,CPU百分比基于实际核心数(单核100%,双核200%,依此类推)。
1580 7
|
监控 开发工具 Android开发
ARMS 用户体验监控正式发布原生鸿蒙应用 SDK
阿里云 ARMS 用户体验监控(RUM)推出了针对原生鸿蒙应用的 SDK。SDK 使用 ArkTS 语言开发,支持页面采集、资源加载采集、异常采集及自定义采集等功能,能够全面监控鸿蒙应用的表现。集成简单,只需几步即可将 SDK 接入项目中,为鸿蒙应用的开发者提供了强有力的支持。
806 114
|
人工智能 自然语言处理 数据可视化
《当传统遇上AI:Tableau与PowerBI的华丽转身》
在数据可视化与分析领域,Tableau和PowerBI长期占据重要地位。随着AI技术的融入,这两款工具实现了全方位升级,极大提升了用户体验。 Tableau新增自然语言交互、智能洞察挖掘和可视化智能推荐功能,降低了数据分析门槛,帮助用户轻松发现隐藏规律并高效制作图表。PowerBI则通过DAX公式智能编写、移动端智能交互和报表智能订阅等功能,简化了复杂计算,实现了随时随地的数据洞察。两者共同开启了数据处理的新时代,为企业决策提供有力支持。
548 12
|
数据采集 数据挖掘 Python
python爬虫去哪儿网上爬取旅游景点14万条,可以做大数据分析的数据基础
本文介绍了使用Python编写的爬虫程序,成功从去哪儿网上爬取了14万条旅游景点信息,为大数据分析提供了数据基础。
1428 1
|
存储 缓存 开发工具
Transformers 4.37 中文文档(十三)(4)
Transformers 4.37 中文文档(十三)
1159 1
|
存储 Linux API
Docker安装 配置
Docker安装 配置
312 2