- 并行編程方法與優(yōu)化實(shí)踐
- 劉文志
- 2025字
- 2019-01-01 01:08:31
1.3.1 如何測(cè)得CPU的浮點(diǎn)峰值性能
一顆CPU的理論浮點(diǎn)峰值性能反映了這顆CPU的最大浮點(diǎn)處理能力,通常也稱為CPU的吞吐量。一般來(lái)說(shuō),CPU浮點(diǎn)峰值統(tǒng)計(jì)的浮點(diǎn)計(jì)算類型只包含乘法和加法(包括減法)。這主要是因?yàn)椋焊↑c(diǎn)乘法和加法構(gòu)成了很多廣泛使用且基礎(chǔ)的重要算法的核心,如矩陣乘法、FFT等。
本節(jié)以Intel Sandy Bridge(簡(jiǎn)稱SNB)和Ivy Bridge(簡(jiǎn)稱IVB)架構(gòu)的CPU為例,介紹如何計(jì)算理論浮點(diǎn)峰值,并實(shí)測(cè)出該峰值。這里以單精度峰值為例,雙精度一般為單精度的1/2,測(cè)試方法也相同。
計(jì)算理論浮點(diǎn)峰值實(shí)際上就是計(jì)算CPU每個(gè)處理核心一個(gè)周期可以處理的浮點(diǎn)乘法和浮點(diǎn)加法的次數(shù)。查看Intel的手冊(cè)知道,在SNB和IVB架構(gòu)下,浮點(diǎn)乘法的延遲是5,吞吐量是1;浮點(diǎn)加法的延遲是3,吞吐量是1。可以得到SNB和IVB的單精度浮點(diǎn)峰值計(jì)算公式如下:
單精度浮點(diǎn)峰值=CPU核心數(shù)×頻率×(8Mul+8Add)
市面上一顆普通的Intel i3 2100的SNB處理器,雙核,頻率是3.1GHz,那么它的單精度浮點(diǎn)峰值就是2×3.1GHz×(8+8)=99.2GFLOPS。
AVX中的vmulps和vaddps指令就是計(jì)算256位單精度浮點(diǎn)乘法和加法的指令。要同時(shí)發(fā)揮乘法和加法的性能,就要求相鄰的乘法和加法指令沒(méi)有依賴關(guān)系,而SNB和IVB架構(gòu)一個(gè)時(shí)鐘周期最多可以發(fā)射4條指令,故處理器的指令發(fā)射能力不會(huì)成為瓶頸。了解了這些信息之后,相應(yīng)的測(cè)試程序也就容易寫了,匯編代碼如代碼清單1-5所示。
代碼清單1-5 測(cè)試SNB CPU峰值性能程序
mov $0x1000000, %rax @ 0x1000000是循環(huán)次數(shù),根據(jù)需要可以改大或改小 vxorps %ymm0, %ymm0, %ymm0 vxorps %ymm1, %ymm1, %ymm1 vxorps %ymm2, %ymm2, %ymm2 vxorps %ymm3, %ymm3, %ymm3 loop: vmulps %ymm1, %ymm1, %ymm0 vaddps %ymm3, %ymm3, %ymm2 subq $0x1, %rax jne loop
代碼中前5行是初始化寄存器狀態(tài),設(shè)置rax為循環(huán)計(jì)數(shù)器,主要在loop循環(huán)內(nèi)不斷執(zhí)行兩條乘法和加法指令。由于SNB架構(gòu)對(duì)add和sub類指令也可以做微指令融合,所以subq和jne兩條指令可以與vmulps和vaddps在同一個(gè)周期發(fā)射。vmulps和vaddps之間沒(méi)有數(shù)據(jù)依賴,前后兩次循環(huán)之間也沒(méi)有數(shù)據(jù)依賴。
其余的工作就是開(kāi)啟和處理器核數(shù)同樣多的C語(yǔ)言線程調(diào)用,且每個(gè)線程綁定到不同的處理器核,然后調(diào)用這個(gè)函數(shù),用計(jì)時(shí)器記錄多線程執(zhí)行的時(shí)間。利用公式16×線程數(shù)×循環(huán)次數(shù)/時(shí)間,即可得到這顆處理器的實(shí)測(cè)GFLOPS峰值性能。在筆者的i3 2100 SNB處理器上實(shí)測(cè)得到97.87GFLOPS,很接近理論峰值99.2GFLOPS。
實(shí)際上,代碼清單1-5在X86處理器上能夠獲得接近峰值的性能有以下原因:
1)寄存器重命名機(jī)制。前后兩次循環(huán)都寫入同一個(gè)寄存器,這是一個(gè)典型的“寫后寫”依賴。如果沒(méi)有寄存器重命名機(jī)制的幫助,那么后一條指令就必須等待前一條指令執(zhí)行完成,形成了一條“完美”的關(guān)于寄存器的數(shù)據(jù)依賴鏈,那么就不可能接近峰值。
2)預(yù)測(cè)執(zhí)行。如果沒(méi)有預(yù)測(cè)執(zhí)行機(jī)制,則下次循環(huán)只能等待循環(huán)條件判斷執(zhí)行完成之后才能開(kāi)始執(zhí)行,這樣就會(huì)基于判斷條件指令形成一條依賴鏈(控制依賴),也就不可能獲得接近峰值的性能。
3)4發(fā)射。循環(huán)內(nèi)部至少有4條指令,如果發(fā)射能力小于4的話,那么發(fā)射能力就成為了瓶頸。比如假設(shè)處理器的指令發(fā)射能力為2,那么一次循環(huán)需要2個(gè)周期才能發(fā)射完,也不可能達(dá)到接近峰值的水平。
4)4條指令發(fā)射到不同的流水線上。如果有兩個(gè)指令發(fā)射到同一條流水線上,那么這兩條指令就必須相互等待(只有一條執(zhí)行完成,另一條才有可能得到執(zhí)行)。而若4條指令發(fā)射到不同的流水線上的話,那么這4條指令可以同時(shí)在不同的流水線上執(zhí)行,即不存在結(jié)構(gòu)化瓶頸。
注意 這個(gè)方法在同一顆處理器上測(cè)出的單核和多核性能,不一定呈線性倍數(shù)關(guān)系,原因在于,現(xiàn)在Intel的處理器很多都有turbo boost技術(shù),會(huì)根據(jù)負(fù)載給處理器自動(dòng)超頻,一般單核負(fù)載時(shí)超頻更高,多核時(shí)較低,甚至完全不超頻。所以除非關(guān)掉turbo boost,或者在沒(méi)有turbo boost支持的處理器上測(cè)試,才可能呈現(xiàn)倍數(shù)關(guān)系。
Intel最新的Haswell架構(gòu)處理器開(kāi)始支持256位的浮點(diǎn)融合乘加指令FMA,即將乘法和加法融合在一條指令中(即a×b+c)。FMA指令的吞吐量是2,延遲是5。由于Intel設(shè)計(jì)的是FMA3指令,即三操作數(shù)的FMA指令,所以在a、b和c三個(gè)輸入向量中,會(huì)有一個(gè)作為輸出結(jié)果。這就導(dǎo)致我們?cè)趯慒MA的峰值測(cè)試程序時(shí),無(wú)法滿足前后兩個(gè)循環(huán)的數(shù)據(jù)無(wú)依賴特征這個(gè)條件,導(dǎo)致下一個(gè)循環(huán)需要等待上一個(gè)循環(huán)的結(jié)果計(jì)算完畢才開(kāi)始執(zhí)行。而FMA的延遲有5個(gè)周期,即兩個(gè)循環(huán)之間的延遲需要5個(gè)周期,這會(huì)極大地拖慢處理速度,也造成了流水線的浪費(fèi)。
為了解決這個(gè)問(wèn)題,測(cè)試程序需要在一次循環(huán)內(nèi)添加足夠多的數(shù)據(jù)無(wú)依賴關(guān)系的FMA指令,將流水線填滿,下次循環(huán)到同一條指令時(shí),上個(gè)循環(huán)的該指令延遲已經(jīng)結(jié)束,可以立即發(fā)射。由于一個(gè)周期可以同時(shí)發(fā)射兩條FMA指令,且延遲是5,那么需要在一個(gè)循環(huán)內(nèi)加入10條FMA指令方能填滿執(zhí)行流水線,如代碼清單1-6所示。
代碼清單1-6 測(cè)試Haswell處理器峰值性能
loop: vfmadd231ps %ymm0, %ymm0, %ymm0 @ 周期0,5,10,15…發(fā)射 vfmadd231ps %ymm1, %ymm1, %ymm1 @ 周期0,5,10,15…發(fā)射 vfmadd231ps %ymm2, %ymm2, %ymm2 @ 周期1,6,11,16…發(fā)射 vfmadd231ps %ymm3, %ymm3, %ymm3 @ 周期1,6,11,16…發(fā)射 vfmadd231ps %ymm4, %ymm4, %ymm4 @ 周期2,7,12,17…發(fā)射 vfmadd231ps %ymm5, %ymm5, %ymm5 @ 周期2,7,12,17…發(fā)射 vfmadd231ps %ymm6, %ymm6, %ymm6 @ 周期3,8,13,18…發(fā)射 vfmadd231ps %ymm7, %ymm7, %ymm7 @ 周期3,8,13,18…發(fā)射 vfmadd231ps %ymm8, %ymm8, %ymm8 @ 周期4,9,14,19…發(fā)射 vfmadd231ps %ymm9, %ymm9, %ymm9 @ 周期4,9,14,19…發(fā)射 subq $0x1, %rax jne loop
本節(jié)以這個(gè)例子作為基礎(chǔ),主要闡釋了浮點(diǎn)運(yùn)算的量化準(zhǔn)則和流水線技術(shù),并初步展示了達(dá)到高浮點(diǎn)吞吐量的基本方法。下面3節(jié)中的例子將會(huì)由簡(jiǎn)入難地展示實(shí)際問(wèn)題在Intel x86處理器下性能優(yōu)化的各種方法和實(shí)戰(zhàn)技巧。
- JavaScript前端開(kāi)發(fā)模塊化教程
- Effective C#:改善C#代碼的50個(gè)有效方法(原書第3版)
- SQL Server 2012數(shù)據(jù)庫(kù)技術(shù)及應(yīng)用(微課版·第5版)
- Cross-platform Desktop Application Development:Electron,Node,NW.js,and React
- C語(yǔ)言程序設(shè)計(jì)
- Hands-On JavaScript High Performance
- 機(jī)械工程師Python編程:入門、實(shí)戰(zhàn)與進(jìn)階
- HTML5 and CSS3 Transition,Transformation,and Animation
- KnockoutJS Starter
- Python之光:Python編程入門與實(shí)戰(zhàn)
- Python程序設(shè)計(jì)與算法基礎(chǔ)教程(第2版)(微課版)
- 實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)(第2版)
- Clojure Web Development Essentials
- ArcPy and ArcGIS(Second Edition)
- Daniel Arbuckle's Mastering Python