本节书摘来自华章出版社《多核与GPU编程:工具、方法及实践》一书中的第1章,第1.4节, 作 者 Multicore and GPU Programming: An Integrated Approach[阿联酋]杰拉西莫斯·巴拉斯(Gerassimos Barlas) 著,张云泉 贾海鹏 李士刚 袁良 等译, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1.4 性能指标
发展多核硬件和开发多核软件的目标是获取更高性能,例如更短的执行时间、更大规模的问题和更大的数据集等。很明显,这需要一个客观的标准或者准则来评估这些努力的有效性。
最起码,一个并行程序的执行时间应该要比其对应的串行程序的执行时间短(然而,并不是所有情况都这样)。执行时间的缩短通常表述为加速比,可用如下公式表达:
(1-1)
其中,对于解决同一个问题实例,tseq是串行程序的执行时间,tpar是并行程序的执行
时间。
tseq和tpar都是时间,但它们并不总客观。二者会受到如下因素影响:
程序员技术水平
编译器(例如,GNU C++与Intel C++)
编译器开关(例如,优化选项关闭或者开启)
操作系统
保存输入数据的文件系统(例如,EXT4、NTFS等)
运行时间(不同的工作负载、不同的网络流量)
为了能够让测得得加速比更具有可信性,需要遵循如下条件。
1.串行程序和并行程序都必须在相同软件和硬件平台以及类似条件下进行测试。
2.串行程序应该是当前最快的解决方案。
其中,第二个条件虽不明显,但是它非常重要。并行算法和与之对应的串行算法完全不同。事实上,一个串行算法可能没有对应的并行版本,甚至可能无法构造其并行本版。
第二个条件非常重要的原因是:实现并行程序所付出的努力(开发成本特别高),只有在获得收益时才有价值。
对于给定的处理器数目,并行程序能够获得的加速比依然严重依赖于输入数据(本节随后将会对这些进行详细说明)。正是由于这个原因,在测试并行程序相对于串行程序的加速比时,往往会大量测试相同大小的不同数据集,甚至会给出最大、最小、平均加速比。
然而,加速比只是问题的一个方面。例如,当加速比大于1时,仅能告诉我们,并行程序可以更快地解决问题。然而,加速比不能反映解决问题的有效性(是否于使用的资源相对应)。因此,第二个性能指标就是效率。通常情况下,效率的定义如下:
(1-2)
其中,N为执行并行程序时所使用的CPU或者计算内核的数目。效率可以理解为,当并行程序执行时每个计算节点 的利用率。效率为100%意味着加速比为N,工作负载平均分配在N个处理器上,每个处理器的利用率为100%(在执行过程中,处理器没有空闲)。当加速比为N时,可以说并行程序获得了线性加速比。
但是,这仅仅是一个理想情况。当多个处理器共同协作完成一个任务时,处理器间会存在通信。这个通信或者通过消息传递进行,或者通过共享资源进行。这些通信将会占用CPU的执行时间,导致加速比小于N。
图1-9显示了利用梯形规则算法计算函数定积分示例程序的加速比和效率。计算负载取决于进行计算的梯形数量。图1-9对应的目标计算平台是i7 950四核CPU,计算结果是将程序运行10遍获得的平均值。
这里有个问题应该要引起读者的注意:如果我们只有一个四核CPU,如何测试和报告8个线程的加速比?
Intel i7 950四核CPU支持一种称为超线程的技术。超线程技术通过复制CPU硬件中的某些部分,允许一个CPU计算内核运行两个软件线程。这使得CPU好像具有两个计算内核。但是,平均只有30%的性能提升,这和理想中的2倍加速比差别较大。图1-9显示了这方面的性能结果。这主要是因为在给定的计算平台上,我们没有8个物理内核来运行8个线程。
效率随线程数目的增多而降低,这是显而易见的。尽管效率降低与特定应用程序相关,但是这在并行程序中是一种常见情况。这归结于并行程序的通信开销,当CPU或者计算内核间的通信增多时,这个开销就会增大。
每一条曲线都对应着不同线程数目的结果(如图例所示)。图a中的理想加速比曲线说明了并行程序性能提升的退化,这是不断增加的通信开销导致的必然结果
图1-9有两个目的:1)给出真实加速比曲线和效率曲线;2)提高正确实验技术的重要性。性能测试应该针对真正的硬件资源,而不是超线程提供的虚拟资源。
图1-9a中的理想加速比曲线是衡量并行程序实现优劣的工具。如前所述,这是性能上限,并不总能达到。
当然,也存在加速比大于N或者效率大于1的情形,这称为超线性加速比。根据效率的定义,这好像是不可能的情况。然而,我们应当知道串行程序处理数据的方式和并行程序不同,两者有不同的执行路径。例如,如果一个程序的目标是在搜索空间中查找某一个值,并行程序可能会更快地找到这个值(相对于使用的计算资源)。它只是通过不同的路径找到这个值而已。
当然,这不是通常情况,可以根据应用和具体输入数据实现。考虑这么一个例子:获取密文的密钥。在DES加密标准中,使用[0, 256-1]间的某一个数字作为将一条消息(明文)转换为晦涩难懂的密文的密钥(key)。在对这个密文进行暴力破解时,需要尝试所有可能的密钥,直到将密文转换为一个可读的文本。假设每次尝试解密这条消息在单个CPU上花费的时间为T,如果这个密钥是数字255,那么串行程序解决这个问题需要花费的时间tseq=(255+1)T。
现在,我们使用两个CPU来解决这个问题。如果我们把包含256个密钥的搜索空间平均分配给两个CPU。例如,第一个CPU搜索[0, 255-1],第二个CPU搜索[255, 256-1]。
那么第二个CPU仅进行一次尝试后,就会找到密钥。那么并行程序的加速比是:加速比,效率是:效率。期望使用更多的计算资源来解决某个问题是非常自然的。即,将计算资源增加到N,从而减少执行时间。这是个谬论!前面所述的简单示例程序就可以证明这点:如果使用3个GPU来解决这个问题会发生什么情况?第一个CPU的搜索空间为: ,第二个CPU的搜索空间为:,第三个CPU的索引空间为。所以,第二个CPU将会在尝试了次后找到正确密钥。那么,并行程序的加速比为加速比,大大低于使用两个CPU时的加速比。
用加速比来表征并行解决方案的有效性,这是有益的还是无益的呢?效率是计算资源利用率的测量方法,分配给程序的计算资源有多少是真正利用到的?效率低证明并行程序设计的比较糟糕,至少证明并行实现需要改进。
最后,我们需要知道当计算资源并且(或者)计算规模增加时并行算法的可扩展性如何。它扩展了吗?
一般情况下,可扩展性表示一个系统有效处理不断增长的工作负载的能力。在并行算法/平台的上下文中,可扩展性表示能够解决更大问题规模或者能够协调使用更多计算资源的能力。
有两个量化可扩展性的指标:强可扩展性和弱可扩展性。
强可扩展性使用同式(1-2)相同的公式来定义:
(1-3)
这是一个关 于数量N的函数。其中,N表示解决同一个问题时,分配的处理器数目。
弱可扩展性同样是关于N的函数,如下表示:
(1-4)
其中,tseq表示使用单个计算机解决问题的时间,t’par表示当问题规模增大N倍时的并行解决时间。
当使用GPU计算资源时,计算可扩展性会遇到很多问题:N的取值应该是多少?GPU一般会拥有成百甚至上千个计算内核。但是我们测试或者报告程序在一个GPU计算内核上的运行时间tseq是不科学的。如果我们这样做,当计算可扩展性时,使用GPU全部的计算内核数目作为N是否合理?同时,GPU是一个托管设备,它需要CPU来执行I/O操作,需要把CPU也计算在内吗?
在这种情况下,可扩展性的计算可以有多种方式。为了避免争议,后面的章节在讨论异构计算平台时,只使用加速比。