|
|
|
|
移动端

3.7.1 零散的可优化部分

《高性能并行珠玑:多核和众核编程方法》第3章HBM上的SIMD与并发优化,本书中展示了如何在处理器和协处理器上进行并行处理和编程——展示了更好利用Intel Xeon Phi协处理器和Intel Xeon 处理器或其他多核处理器的系统计算潜力的最有效的方法。本节为大家介绍零散的可优化部分。

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

技术沙龙 | 6月30日与多位专家探讨技术高速发展下如何应对运维新挑战!


3.7.1 零散的可优化部分

在处理源代码的过程中,我们发现了一些零散、细小的可优化部分。例如间接引用、假定形状参数和k个循环的最内层循环分支。在我们集中精力调整生成SIMD代码的同时,我们将列出几个能够转化为性能提升的零碎可优化部分样例。图3-13~图3-15展示了对初始化需要重写部分的优化伪代码步骤。原始代码中的起始点如图3-13所示。

我们发现原始代码中的间接寻址来自三维索引查询表mmk(i,jj,k)。这个数组将网格点索引数据集(i,jj,k)转换到与之对应的湿点索引上,如果(i,jj,k)表示的是在陆地上或海平面以下的湿点那么就返回0值。如同数据结构中的说明一样,我们可以使用更少的存储和直接寻址方式从msrf(i,j)、mcol(iw)和kh(iw)数组中获得相同的信息。另外两个障碍是假定形状参数和最内层循环的分支,它们可以通过把代码转换到片段中(见

图3-14)处理(在后面的介绍中我们去掉了额外工作部分,目的是详细描述调优版本所需的关键步骤)。

在伪代码段中,我们使用foo(i,j,k)作为在网格点(i,j,k)上评估更复杂表达的缩写符号;因此foo并不是代表着数组查找或函数调用。

换而言之,点(i,jj,k)上的t1是同一列(i,jj)上的t2项或从邻居列(i, jj+1)到右侧的相似项。注意,虽然图3-13中代码段由于使用间接寻址能够一直执行k循环的底部,但如果我们想要在两个主k循环中保留纯粹的跨度减1,那么我们必须在图3-14的代码段中保留一个循环。然后,我们发现把组合中带有两个其他数组hx和u的t1表示为:

以至于我们推断出的结果还不如使用系数:

主要原因不在于if-else分支的判断语句上,而是所有操作的两次执行上。现在我们的目标就是要消除多余的两次执行过程。首先,我们发现需要同时计算(i,jj)和(i,jj+1)项并由以下代码做出选择:

但当程序执行到右侧jj+1的邻居列时,我们还要在点(i,jj+1,k)上再做一次foo计算。而此时会得到MAX()的权重,而不是MIN()的。

另一方面,我们应该在只运行一次的地方考虑使用“两级火箭”优化。例如,在(i,j,k)位置对所有的湿点(i,j,k)做foo计算,在临时数据(t4)上进行存储,以及最后使用最大或最小函数把它存储到t1中。图3-15展示了该伪代码片段。

上述转换过程对编译器是透明的,并且它将生成SIMD优化代码。然而,这些转换不足以生成高效的SIMD代码。因此下一步的代码生成和代码轮廓调整工作为进程的优化提供了指导。我们必须确保适当均衡的计算强度和合理的缓存压力。我们通过减少缓存刷新的循环次数数量的方式对后者进行了分析,而对前者做了设计选项的要求。在本章特定的9点stencil模板计算应用程序中,我们有两种选择。我们可以试图通过将循环拆分为两个子循环的方式最大化向量化长度。这些循环主要是指处理stencil(如iw)中点的循环,例如带有两个分支语句的iw,在8点邻居上做额外操作的循环kh(iw)。事实上,如果能够还原,邻居循环也可以拆分为8个子循环。此外,我们还可以通过构造大的循环结构来同时处理stencil的中点和它的8个邻居。但要确保跨度减1访问的步长数必须是9列长度的最小值kmin。然后,需要在长度超过kmin的列中执行这8次循环。通过依次分析循环中的示踪剂平流代码后我们发现,后一种设计(具有一个大循环和剩下的不超过8个循环数)比拆分为多个(不超过9个)小循环方法的性能要好许多。


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

51CTO读书频道二维码


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

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

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

读 书 +更多

计算机网络技术

本书是为北大燕工教育研究院编写的计算机网络技术的学习教材。它以实际教学大纲为依据,全面系统的介绍了计算机网络技术知识,对于一个...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊