|
|
|
|
移动端

2.4.4 内存使用

《高性能并行珠玑:多核和众核编程方法》第2章从正确到正确&高效:Godunov格式的Hydro2D案例学习,本章将探讨一段科学模拟代码,这段代码是一个以气体动力学为基础的模拟程序。这份程序的输出结果正确,但(初始版本)性能欠佳。本节为大家介绍内存使用。

作者:张云泉 等译来源:机械工业出版社|2017-11-14 17:42

技术沙龙 | 邀您于8月25日与国美/AWS/转转三位专家共同探讨小程序电商实战

2.4.4 内存使用

在原始的代码中,slab方法使用的类GPU内存模型,这种方法并没充分利现代系统的内存层次结构。

从slob复制进和复制出数据的开销并不能与其他计算重叠,而且这种操作计算密度较低。更糟糕的是,slab计算使用了很多中间变量,这些中间变量急剧提升了内存占用率。这些问题有时可以通过中间存储的重用得到缓解,但是在每次更新中对小区域的依赖性表明应该使用不同的方法解决这个问题。

完善compute_deltat()。独立计算每个时间步长会导致性能下降,除此之外,因为安全地进入和退出遍历需要使用同步,所以它需要重读整个网格并降低速度;这也会成为巨大的损失。

事实上,时间步长的计算只在计算开始阶段和在奇数步中遍历x轴后才会发生。除第一次之外,compute_deltat()函数将读取的数据和奇数步后x轴遍历最后一部分积分的数据是相同的,积分后计算决定每个单元格中最大传播速度,而最大传播速度决定了固定时间步长。

全局最大速度的归约的计算可以作为work-sharing的一部分,work-shareing是在每次更新步中都要做的工作。在遍历时每个线程独立地计算并本地归约所需要的最大速度,同时时间步循环可以在线程专有的值上协调一个全局归约。如果通信成本占了主要消耗,此操作可使用树形结构实现。

通过结合compute_deltat()和积分步,可减少网格遍历和同步的花销。

旋转更新。图2-7中垂直箭头展示了流量计算和积分在步间的依赖性;对于计算网格的一维的行(或者列),这里既有重用,但也有依赖性的“窗口”。

沿着每个网格strip通过使用“旋转”以完全重用中间计算和最小化中间存储是可行的。

首先,更新中的全部的slab变量被“收缩”,即,constoprim()/conservative_to_primitive()、slope()、trace()、riemann()、cmpflx()和updateConservativevars()/update();qleftright()除了复制数据并没有真正工作,我们将其移除。这些函数同时在一个单元格中运行;同时这些函数使用子问题所需要的最少输入集合,并且通过输出参数返回结果的向量值。

在strip更新开始的时候,priming阶段使用边界条件(通过调用set_boundaries()),即装载合适的conservative变量,接着计算决定左边界流量所需要的数据(即,图2-7中在x0处的流量)——所有有用的中间值保存在环形缓冲区中,这些值可能要用于之后网格的更新,同时所有其他中间值被舍弃。参考strip_prime()(图2-10,参考图2-9中的描述)实现这部分代码。

之后,为了更新strip中所有网格,在stable阶段,加载环形缓冲区存储的数值和strip中接下来需要的conservative变量,接着计算下一次流量计算所需要中间值。前一步中的流量和最新计算的流量在图2-7j阶段结合在一起,用于更新当前的网格,同时把未来stable步所需要的中间值放置进了环形缓冲区中。参考strip_stable()(见图2-11)。

图2-7表明,在图2-7i中对xi上单流量的依赖最宽的点是图2-7d阶段中第二轮primitive变量的运算——最后结合四个值算出结果。因此没有环形缓冲区包含多于四个值,这就保持了中间存储的成本较低。


喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

Ubuntu Linux入门到精通

本书全面介绍了Ubuntu Linux的相关知识,内容详实,论述清晰。主要内容包括Ubuntu介绍、文件系统管理、进程管理、压缩与查询系统、Shel...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊