12.2 测试程序集
中国有句古话:是骡子是马拉出来遛遛。衡量计算机性能最好的办法是在计算机上运行实际程序。但计算机的性能依赖于它的应用领域,这些应用可以是CPU计算密集型(如科学计算)、IO密集型(如Web服务器)或者访存密集型(如视频编辑)的。那么怎样评价计算机系统的性能,采用什么样的测试程序来评价计算机系统的性能?一种办法是采用计算机上的日常任务来衡量,如:用办公软件Office打开一个大的Word文档并上下翻页,看看是不是会卡;用压缩程序压缩一个目录文件,看看多长时间能完成压缩;用浏览器打开一个网址,看看网页装载的时间是多长。然而这种测试计算机系统性能的方法没有普适性,也很难有量化的可比性。可能一台计算机运行程序A比另一台快,但运行程序B却比另一台慢。我们需要一些公共和通用的测试程序,这些测试程序需要考虑公平性、可量化、可移植等因素。为了相对公平地比较不同计算机系统的性能,逐步形成了许多专门用于性能评价的基准测试程序集。本节将介绍一些比较常见的基准测试程序集。
用于性能评价的测试程序一直以来是有争议的,因为很难定义和识别具有代表性的测试程序。早期人们曾使用MIPS、MFLOPS或者平均指令延迟等简单的指标来评价系统的性能。后来,性能评价主要是通过执行小的测试程序,例如从应用中抽取出来的kernels(如Lawrence Livermore Loops)、Dhrystone和Whetstone测试程序、Linpack、排序算法、埃拉托斯特尼筛法(Sieve of Eratosthenes)、八皇后问题、汉诺塔(Tower of Hanoi)等。再后来,出现了类似SPEC和TPC这样的组织,它们致力于为各种重要的工作负载(包括通用工作负载、Java工作负载、数据库工作负载、服务器工作负载、多媒体工作负载和嵌入式工作负载等)建立合理的基准测试程序集。除了尽可能准确地反映实际工作负载的行为,基准测试程序集还应该努力给出易于理解、容易比较的数值来体现测试结果。如已经获得了一组测试程序中每个程序的分值,可以通过算术平均、几何平均或者调和平均三种求平均的方法,找到一组数字的中心趋势,获得该程序集的数值。
采用基准测试程序对计算机和处理器进行性能分析,发现系统的瓶颈并对系统进行改进,是计算机系统设计中的重要工作。
12.2.1 微基准测试程序
在处理器的设计过程中,尤其是在微体系结构的设计空间探索的过程中,我们希望有一类小的测试程序,能在很短的时间内跑完,可在模拟器、RTL仿真模型或者FPGA平台上执行,覆盖微体系结构的特性,如分支预测器的精度、Cache的行为、流水线的效率、各项队列大小、重命名寄存器数目和功能部件数量的影响等,这就导致了微基准测试程序(简称微测试程序)的出现。在处理器性能测试和分析中,常用的微基准测试程序包括Sim-alpha的microbench、bp_microbench、LMbench、STREAM、Coremark、Coremark-pro和Unixbench等。
微测试程序(microbench)是一系列很小的测试程序或者代码片段。得克萨斯大学奥斯丁分校的R.Desikan和Doug Burger在设计Sim-alpha模拟器的时候,为了将Sim-alpha模拟器和真实处理器Alpha 21264进行校准,设计了一系列的微测试程序。这些测试程序对处理器核的某个模块进行了测试,同时排除了处理器其他模块的影响,所以特别适合处理器设计时对某个模块的选择和优化,例如分支预测器模块、执行单元模块和访存流水线模块,这几个模块可以较准确地反映流水线的效率。下面的图12.1中给出了部分微测试程序。第一行用于测试指令流水线的前端(front-end),例如行预测器的实现和分支预测器的实现,C表示测试的控制流;第二行用于测试指令流水线的执行核心(execution core),例如调度和发射逻辑(scheduler),E表示执行核心;最后一行用于测试内存系统的参数,例如一级Cache的延迟、二级Cache的延迟和内存的延迟,M表示内存系统。微测试程序更为详细的描述见参考文献[38]。Sim-alpha的微测试程序的源代码可以从网站http://www.cs.utexas.edu/users/cart/code/microbench.tgz下载。
阿拉巴马大学亨茨维尔分校的A.Milenkovic给出了一系列和分支预测器相关的微基准测试程序集,用于测试微体系结构中和分支预测器相关的参数,例如跳转目标缓存(Branch Target Buffer,简称BTB)的组织、全局历史寄存器的位数和局部预测器每一项的位数等。这些微测试程序可以用于编译器的代码优化,也可以用于处理器设计中对于各种分支预测器组织的性能评估,其网站(www.ece.uah.edu/~lacasa/bp_mbs/bp_microbench.htm)上给出了相关的代码。
其中GenCode.c程序用于处理器中BTB结构参数的测试,基本思想是构造一个微测试程序,在一个loop循环中包含B个条件分支指令,每个条件分支指令如jle和jle之间(LoongArch为bne和bne之间)的距离为D,如果增加B的大小和D的大小,所有的条件分支指令都能装载到BTB中,也就是说,当B等于NBTB-1,其中NBTB为BTB的项数,则分值误预测率趋近于零,这样就可以判断处理器中BTB的相连度和项数。
图12.1 微基准测试程序集
Step1.c到Step6.c程序用于处理器中条件分支预测器的测试,基本思想是在微测试程序中插入间谍分支(spy branch)语句,通过硬件计数器来获得该间谍分支的分支误预测率,由此判断条件分支预测器的内部结构和行为。例如在Step1.c程序中,for循环中只有唯一的条件分支语句,if((i%L)==0)语句在X86中被编译为jne指令(LoongArch为bnez指令),for循环语句被编译为jae和jmp指令(LoongArch为bne和b指令),如果1表示taken,0表示not taken,如当LSpy为8时,该分支历史模式为11111110,假定局部历史模式的长度为L,当LSpy小于或者等于L时,分支误预测率趋近于0,当LSpy大于L时,每LSpy次间谍分支发生误预测一次,这样通过不断增加LSpy的大小并得到该程序的分支预测率来获得局部预测器中历史模式长度L的大小。
LMbench是由HP以色列海法实验室开发的一套微测试程序集,可以测量许多和系统性能相关的因素。LMbench采用ANSI C编码、POSIX接口,是个多平台开源基准测试程序,能够测试包括文件读写、内存操作、进程创建和销毁开销、网络等性能。一般来说,LMbench衡量两个关键特征:延迟和带宽。带宽就是系统中搬运数据的能力,如各级Cache的带宽、内存的带宽、缓存的IO带宽等,测量的方式包括bcopy库、手工循环展开bcopy、直接从内存中读、非拷贝的写、管道、进程间通信和TCP套接字等,可以采用read和mmap的API接口。延迟是系统的反馈时间或者开销,如各级Cache的访问延迟、内存访问的延迟和操作系统中某一项功能的开销,包括信号处理的开销、进程创建的时间、上下文切换的时间、进程间通信的开销、文件系统的延迟和磁盘的延迟等。Sun公司在开发UltraSPARC和Intel公司在开发Pentium Pro的过程中都曾经使用LMbench用于发现微处理器设计上的性能瓶颈,Linux操作系统在kernel开发的性能调优中也曾使用这些工具。表12.3给出了LMbench测试程序集的各种工具及测试说明。
表12.3 LMbench微测试程序集
STREAM基准测试程序测量计算机的可持续内存带宽。STREAM是一个简单的合成测试程序,主要是测量内存的带宽(MB/s)和简单向量核心代码的计算速率。它由John McCalpin在特拉华大学执教的时候开发,并在随后成为工业界的标准测试程序,其有Fortran和C的代码,也有单处理器和多线程的版本,多线程版本包括OpenMP和MPI的并行。如表12.4所示,STREAM测试程序由Copy、Scale、Add和Triad四部分组成,测试了4个循环,并给出不同的内存带宽峰值。STREAM的基本原则是每个数组必须不小于最后一级Cache(LLC)大小的4倍或者100万个元素(取两者中较大的)。通常内存带宽比单线程STREAM测出来的值要高,为了能达到内存的饱和带宽,可以采用两种方法:一种是吞吐量的方法,执行多个stream的实例;另一种是执行OpenMP的版本。基于标准的STREAM测试程序,可以衍生出其他测试内存带宽的程序,改变数组访问跳步stride=1的简单循环,采用stride=N的操作(N=2,3,4,5,6,7,8,9,10,20,40),采用反向的(stride=-1)循环以及基于索引的操作,包括load采用索引的数组和store采用索引的数组。
表12.4 STREAM基准测试程序
CoreMark是一个综合性的基准测试程序,主要用于测量嵌入式系统中CPU的性能,2009年由嵌入式微处理器基准测试协会(英文简称EEMBC)开发,用于取代过时的Dhrystone测试程序。其代码使用C语言编写,主要执行:列表操作(列表的插入和删除、反转列表和排序等),矩阵运算(矩阵加、矩阵常量乘、矩阵向量乘、矩阵和矩阵的乘),简单状态机(扫描字符串进行状态转换,主要测试switch-case和if语句的行为),CRC运算(测试循环冗余校验运算和用于测试过程的自检)。CoreMark程序有很多优点,如代码量很小、可移植性高、很容易理解、免费以及测试结果为单一分值。CoreMark避免了Dhrystone所存在的一些问题:首先,CoreMark程序中的运算所需要的值不会在编译的时候产生,这样就能确保编译器不会在编译时预计算结果,从而减少了编译器优化选项的干扰;其次,CoreMark没有调用库函数;最后,测试结果为单一分值,衡量每秒钟执行了多少次迭代,便于不同处理器之间分值的比较。
CoreMark-Pro是EEMBC组织推出的并行基准测试程序,用于处理器流水线、存储子系统和多核等综合性能测试,其包含5类定点应用和4类浮点应用,如JPEG压缩、ZIP压缩、XML解析、SHA-256算法和FFT、求解线性代数和神经网络算法等。
UnixBench是一款测试类UNIX系统基本性能的工具,主要测试项目如表12.5所示。其中,Dhrystone测试的核心为字符串处理,Whetstone用于测试浮点运算效率和速度。这些测试规模比较小,容易受编译器、代码优化、系统库以及操作系统的影响而产生波动。
表12.5 UnixBench测试项目
12.2.2 SPEC CPU基准测试程序
基准测试程序中最重要的一类就是SPEC组织推出的SPEC CPU系列测试程序集。SPEC是由计算机厂商、系统集成商、大学、研究机构、咨询公司等多家单位组成的非营利组织,这个组织的目标是建立、维护一套用于评估计算机系统的标准。SPEC组织创建了SPEC CPU系列测试程序集,主要关注CPU的性能,如SPEC CPU89、SPEC CPU92、SPEC CPU95、SPEC CPU2000、SPEC CPU2006和SPEC CPU2017。SPEC基准测试程序来自真实的程序,做了适当的修改,主要是为了可移植性和减少IO影响。SPEC测试代表了绝大多CPU密集型的运算,包括编程语言、压缩、人工智能、基因序列搜索、视频压缩及各种力学的计算等,包含了多种科学计算,可以用来衡量系统执行这些任务的快慢。SPEC CPU测试中,测试系统的处理器和编译器都会影响最终的测试性能,而磁盘、网络等IO和图形子系统对于SPEC CPU的影响比较小。SPEC CPU基准测试程序特别适用于桌面系统和单CPU服务器系统的CPU性能测试。
表12.6~表12.8分别是SPEC CPU2000、SPEC CPU2006和SPEC CPU2017具体的测试项目和说明。
表12.6 SPEC CPU2000程序及描述
表12.7 SPEC CPU2006程序和描述
表12.8 SPEC CPU2017程序和描述
SPEC CPU2000包括12个定点测试程序(CINT2000)和14个浮点测试程序(CFP2000)。定点测试程序包括C编译器、VLSI布局和布线工具、图形应用等。浮点测试程序包括量子色动力学、有限元建模和流体动力学等。测试机的内存应不小于256MB,以确保满足所有程序运行时的内存需求。
SPEC CPU2006对SPEC CPU2000中的一些测试程序进行了升级,并抛弃和加入了一些测试程序,以更好地反映当时主流应用的特性。SPEC CPU2006包括12项整数运算和17项浮点运算。SPEC CPU2006的工作集变大了一些,对测试机的最小内存需求是1GB。
SPEC CPU2017是SPEC组织于2017年再次更新的CPU基准测试程序集,包含43个基准测试程序,分为4个测试程序集,两个定点程序集SPECrate 2017 Integer和SPECspeed 2017 Integer,以及两个浮点程序集SPECrate 2017 Floating Point和SPECspeed 2017 Floating Point。CPU2017的工作集变得更大了,如SPECspeed需要最小16GB内存,SPECrate在64位系统中的每份拷贝最小需要2GB内存。
为了便于比较,SPEC CPU产生一个分值来归纳基准程序的测试结果。具体方法是将被测计算机的执行时间标准化,即将被测计算机的执行时间除以一台参考计算机的执行时间,结果称为SPECratio,SPECratio值越大,表示性能越好。综合测试结果是取所有程序SPECratio的几何平均值,所有定点程序的平均值称为SPECint,所有浮点程序的平均值称为SPECfp。为了测试多核系统的吞吐能力,SPEC CPU还可以测试多个CPU核同时执行多份程序拷贝时的性能,并且把CPU的时间转换为SPECrate分数。SPEC CPU 2017略有不同,SPECspeed 2017允许通过OpenMP或者自动并行化对单个程序进行多线程并行化的执行,测试的是系统多线程的性能,而不仅仅是单核单线程的性能,它的程序集也和SPECrate不完全相同。
12.2.3 并行系统基准测试程序
并行计算机系统(多核、多线程和多处理器系统等)和单计算机系统不同的是,其存在并行性的瓶颈,包括多个线程之间共享资源的竞争和算法中数据的相互依赖等。面向并行系统的基准测试程序就是测试和评价并行系统的性能,在并行计算机体系结构的研究中起着重要的作用。这里主要介绍SPLASH-2、PARSEC和Linpack三种并行基准测试程序集。
(1)SPLASH-2
1992年,斯坦福大学推出了并行测试程序SPLASH(Stanford ParalleL Applications for SHared memory),1995年推出了SPLASH-2。SPLASH-2使用C语言编写,由12个程序组成,使用Pthreads API并行编程模式。SPLASH-2包含4个核心程序:Cholesky将一个稀疏矩阵拆分成一个下三角矩阵和它的转置的积;FFT用于计算快速傅里叶变换;Radix是分配存储地址的算法;LU用于将一个稀疏矩阵拆分成一个下三角矩阵和一个上三角矩阵的积。另外还包含8个应用程序:Ocean用于通过海洋边缘的海流模拟整个海洋的运动;Radiosity用于模拟光线在不同场景下的光影现象;Barnes用于模拟一个三维多体系统(例如星系);Raytrace使用光线追踪渲染了三维的场景;FMM采用了自适应快速多极子方法模拟了两维体系统的相互作用;Volrend使用光线投射算法渲染三维体;Water-Nsquared采用预测校正法评价了水分子系统的力和势能;Water-Spatial采用了三维格点算法评价了水分子系统的力和势能。
(2)PARSEC
2008年,普林斯顿大学推出了PARSEC(The Princeton Application Repository for Shared-Memory Computers)。它最早来自Intel公司和普林斯顿大学的合作项目,目标是提供一个开源的并行测试程序集,主要面向新兴的应用,能评价多核处理器和多处理器系统,应用包括金融计算、计算机视觉、物理建模、未来媒体、基于内容的搜索和重复数据删除等。2009年推出PARSEC 2.1版本,PARSEC 2.1包括13个应用。2011年推出PARSEC 3.0,PARSEC 3.0支持网络的应用,以及更便利地增加新的工作负载。PARSEC能支持多种输入集,包括test、simdev、simsmall、simmedium、simlarge和native,sim输入集主要用于输入到模拟器的程序测试,native输入用于在多核和多处理器的真实的机器中进行测试。PARSEC通常采用Ptherads、OpenMP和Intel TBB三种并行编程模式,表12.9给出了PARSEC的应用和并行模拟、并行粒度、数据共享和数据交换的量以及每个应用所支持的并行编程模式。
表12.9 PARSEC并行测试程序集
(3)Linpack
Linpack是线性系统软件包(Linear system package)的缩写,开始于1974年,由美国阿贡国家实验室应用数学所主任Jim Pool提出并设计,是一套专门解线性系统问题的数学软件。Linpack用于用高斯消元法求解一元N次稠密线性代数方程组的测试,当前在国际上已经成为最流行的用于测试高性能计算机系统浮点性能的基准测试程序。Linpack测试包括三类,Linpack100、Linpack1000和HPL。Linpack100求解规模为100阶的稠密线性代数方程组,它只允许采用编译优化选项进行优化,不得更改代码,甚至代码中的注释也不得修改。Linpack1000求解规模为1000阶的线性代数方程组,达到指定的精度要求,可以在不改变计算量的前提下做算法和代码的优化。HPL即High Performance Linpack,也叫高度并行计算基准测试。前两种测试运行规模较小,已不适合现代计算机的发展,因此现在使用较多的测试标准为HPL。HPL是针对现代并行计算机提出的测试方式,用户在不修改任意测试程序的基础上,可以调节问题规模的大小N(矩阵大小)、使用的CPU数目和使用各种优化方法等来执行该测试程序,以获取最佳的性能。衡量计算机性能的一个重要指标就是计算峰值,浮点计算峰值是指计算机每秒能完成的浮点计算最大次数。理论浮点峰值是该计算机理论上能达到的每秒能完成的浮点计算最大次数,它主要是由CPU的主频决定的。理论浮点峰值=CPU主频×CPU每个时钟周期执行浮点运算的次数×系统中CPU核数。实测浮点峰值是指Linpack测试值,也就是在这台机器上运行Linpack测试程序,通过各种调优方法得到的最优的测试结果。用高斯消元法求解线性方程组,当求解问题规模为N时,浮点运算次数为(2/3×N3+2×N2)。因此,只要给出问题规模N,测得系统计算时间T,系统的峰值=计算量(2/3×N3+2×N2)/计算时间T,测试结果以浮点运算每秒(FLOPS)给出。一般程序的运行几乎不可能达到Linpack的实测浮点峰值,更不用说达到理论浮点峰值了。这两个值只是作为衡量机器性能的一个指标,用来表明机器的处理能力和潜能。
12.2.4 其他常见的基准测试程序集
SPECjvm2008是一种通用的多线程Java基准测试工具,它能够反映Java运行时环境(Java Runtime Environment,简称JRE)的性能表现,其中JRE包含Java虚拟机(JVM)标准实现及Java核函数库。SPECjvm2008测试程序集包含编译、压缩、加解密、数据库、音频解码、FFT和LU等科学计算、sunflow和XML等22个测试程序,给出的测量结果是每分钟执行了多少个操作。该套测试工具主要体现处理器和内存子系统的性能,与IO关系不大。
SPECjbb2005是SPEC组织推出的服务器端Java基准测试程序,用于测试服务器端的Java运行时环境的性能。SPECjbb2005基于IBM内部的测试程序pBoB,模拟了当前最典型的三层架构中服务器端的Java应用,其中客户端(或称为驱动)用于产生负载,中间层实现了商业逻辑和更新数据库,数据库层使得这些更新永久保存,主要测试基于Java中间层商业逻辑引擎的性能。该基准测试程序在软件层面对Java虚拟机(JVM)、即时编译器(JIT)、垃圾收集器(GC)、用户线程以及操作系统的某些方面施加了压力,在硬件层面测试了CPU、存储层次的性能,对磁盘和网络IO没有施加压力,测试给出的结果表示为每秒完成多少笔业务操作,即BOPS(Business Operation Per Second)值。
SPECSFS是文件服务器测试程序,其使用一个文件服务器请求的脚本来测试NFS的性能,测试了IO系统(包括磁盘和网络IO)和CPU的性能。SPECWeb是一个Web服务器测试程序,模拟了多个客户端请求,包括静态的和动态的服务器的页面请求,以及客户端把页面数据传输到服务器。
TPC事务处理测试程序。事务处理性能委员会(Transaction Processing Performance Council,简称TPC)组织建立了一系列真实的事务处理测试程序。TPC事务处理测试程序测量了系统处理事务的能力,其中TPC-C于1992年创建,模拟了一个复杂的查询环境;TPC-H模拟了即席查询和决策支持系统;TPC-R模拟了商业决策支持系统;TPC-W是基于Web的事务测试程序,模拟了面向商业的事务Web服务器。所有的TPC测试程序测量性能的标准是每秒执行了多少个事务(TPS)。
SPECviewperf是SPEC组织推出的图形测试程序,用于测试3D渲染的性能。SPECviewperf使用真实应用中提取的OpenGL图形记录,并使用一个3D建模和系列OpenGL调用来转换这个模型以获得原始的帧数,用于测量运行在OpenGL应用程序接口之下的系统3D的图形性能。
Octane基准测试套件是Google推出的用于评估浏览器中JavaScript性能的基准测试工具。Octane 1.0包含13个测试程序,Octane 2.0包含17个测试程序。例如Richards程序为模拟操作系统内核行为的测试程序,pdf.js程序采用JavaScript实现了Mozilla的PDF Reader程序,它测量了pdf文件的解码和解释的时间,其他更为详细的介绍参见网址https://developers.google.com/octane/benchmark。
在计算机系统性能分析中,基准测试程序起着非常重要的作用,我们不仅仅只是用它们来跑个分值,更需要深入分析测试程序的行为特性,包括与体系结构无关的特性、与体系结构相关的特性,以及对计算机系统哪一部分施加压力等。