最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

從納秒級(jí)優(yōu)化談CPU眼里的好代碼

2022-01-21 15:15 作者:Boolan博覽  | 我要投稿

編者按:本文摘錄自「全球C++及系統(tǒng)軟件技術(shù)大會(huì)」張銀奎老師的專題演講。


1.現(xiàn)代CPU的偏好

今天,CPU眼里的好代碼和我們平常理解的好代碼是有區(qū)別的??梢运伎家幌?,以下兩條語(yǔ)句CPU的執(zhí)行速度是一樣的嗎?

A=B*0.01 和 A=B/100.0

答案是不一樣的。那我們來(lái)看看究竟有多大差別。

再來(lái)看看輸出結(jié)果。


現(xiàn)在CPU內(nèi)部的結(jié)構(gòu)涉及到亂序執(zhí)行、多流水線、多端口等邏輯。那如果拿Intel的Ice Lake客戶端的微架構(gòu)來(lái)看,可以分為前端和后端。前端可以看作高速的解碼指令設(shè)施,把宏指令—英特爾X86指令解成V指令,放在V指令的隊(duì)列里,下面是可以亂序執(zhí)行的后端。下方顯示的后端是多端口,每個(gè)端口都可以發(fā)射指令。前端可以理解為酒店前臺(tái),但是有沒(méi)有空房,能否安排入住還是得看后端。


現(xiàn)如今,內(nèi)存的壓力是很關(guān)鍵的約束,計(jì)算機(jī)計(jì)算的數(shù)據(jù)需要從內(nèi)存取得,導(dǎo)致內(nèi)存供應(yīng)不上。蘋(píng)果推出的M1最大的革新就是增大了CPU和內(nèi)存之間的帶寬,釋放了Memory Bound,因此取得很好的效果。


除法是現(xiàn)在CPU很難執(zhí)行的操作,大家學(xué)過(guò)復(fù)制電路的話應(yīng)該可以理解,除法操作需要很復(fù)雜的計(jì)算,因此它的流水線特別長(zhǎng),導(dǎo)致執(zhí)行流水線壓力特別大。


如果有十個(gè)端口,將它比喻成跑道,跑道的能力是不同的,當(dāng)遇到加法指令,很多個(gè)端口都可以執(zhí)行,但是對(duì)于除法指令,只有一個(gè)端口可以執(zhí)行。普通的加減乘數(shù)學(xué)運(yùn)算或是位運(yùn)算,可以在多個(gè)端口執(zhí)行,但是對(duì)于除法和個(gè)別的復(fù)雜指令,只有一個(gè)端口可以執(zhí)行,并且開(kāi)銷很大,不同的CPU也會(huì)有細(xì)微的差別。

上圖中我們可以看到latency是49-135個(gè)ticks,即跑一條除法指令需要49-135個(gè)時(shí)鐘,然而普通的加法指令只需要一個(gè)時(shí)鐘,并且理論上最多可以跑四條跑道,因此除法指令和加法指令需要的時(shí)鐘周期差距懸殊。


我們可以通過(guò)以上的例子發(fā)現(xiàn),CPU執(zhí)行不同的指令所花的時(shí)間是十分懸殊的。如果把這個(gè)代碼稍微改一改,將乘除累加到不同的變量上,它的性能會(huì)稍微好一點(diǎn),但是仍然除法會(huì)比較慢。


2.數(shù)據(jù)結(jié)構(gòu)定義

再來(lái)看看下面這個(gè)問(wèn)題:寫(xiě)右側(cè)school_s結(jié)構(gòu)體的i和n成員的速度一樣么?


上圖中寫(xiě)了編譯器不要自動(dòng)做對(duì)齊,即按字節(jié)確定邊界。比如,double是八個(gè)字節(jié),int是四個(gè)字節(jié),char是一個(gè)字節(jié),int n如果沒(méi)有pack(1)的話,編譯器會(huì)給它至少分四個(gè)字節(jié),int n在四字節(jié)的邊界??偟膩?lái)說(shuō),編譯器的默認(rèn)思想是,字段是多長(zhǎng),偏移地址就一定是可以整除的。比如是四個(gè)直接的整數(shù),那這段的偏移一定是4、8、16、24這樣的偏移值。但是如果加了pack(1),它會(huì)給它做緊縮,只分一個(gè)字節(jié),int n就不對(duì)齊了。


給大家看一下內(nèi)儲(chǔ)類的布局,如果上這個(gè)調(diào)制器,觀察一下n的位置。起始位置是對(duì)齊的,都是0,一行是16個(gè)字節(jié),n就不對(duì)齊了,n的起始位置大概是13、14、15、16,有一個(gè)字節(jié)被移到下面了。這就叫不對(duì)齊的整數(shù),對(duì)不對(duì)齊的整數(shù)要慎重。

訪問(wèn)對(duì)齊的和訪問(wèn)不對(duì)齊的速度一樣嗎?答案是不一樣的,并且訪問(wèn)不對(duì)齊的要慎重。那訪問(wèn)不對(duì)齊的影響有多大呢?接下來(lái)還是用數(shù)據(jù)來(lái)看。這個(gè)問(wèn)題對(duì)現(xiàn)代CPU來(lái)說(shuō)變得更加“詭異”,對(duì)于讀寫(xiě)還不一樣,那到底是寫(xiě)不對(duì)齊的還是讀不對(duì)齊的?這個(gè)影響還不同。


下面用一段代碼來(lái)測(cè)一測(cè)。

現(xiàn)在的CPU,如X86,0、1、2這三條地址線是沒(méi)有的,一寫(xiě)就是64位的數(shù)據(jù)總線,以八個(gè)字節(jié)為邊界來(lái)寫(xiě),因此不對(duì)齊的可能要寫(xiě)兩次,因?yàn)閷?xiě)的時(shí)候都是以地址總線對(duì)齊的邊界來(lái)寫(xiě)。如果你不對(duì)齊寫(xiě)兩次,那多余的這部分要用屏蔽機(jī)制把它掩蓋掉,所以硬件處理起來(lái)很費(fèi)勁,開(kāi)銷大。

當(dāng)我們用VTune觀察這樣內(nèi)存賦值,這時(shí)候Core Bound和Memory Bound都很大,即執(zhí)行引擎和內(nèi)存都很有壓力。因?yàn)閳?zhí)行引擎執(zhí)行這樣的不對(duì)齊指令需要做特殊處理—不對(duì)齊的位操作。在CPU層面,在寫(xiě)這樣的內(nèi)存的時(shí)候也是需要多花精力。在我們用VTune優(yōu)化時(shí),紅色代表某個(gè)環(huán)節(jié)發(fā)生擁堵,綠色代表暢通。


因此,讀寫(xiě)沒(méi)有按邊界對(duì)齊的整數(shù)會(huì)讓我做很多無(wú)用功,寫(xiě)比讀更懸殊。當(dāng)我們做循環(huán)的讀時(shí),CPU內(nèi)部會(huì)用所謂的向量化指令把把損失做一些彌補(bǔ)。


3.大數(shù)組的定義


接下來(lái)我們來(lái)看第三個(gè)案例,這是一個(gè)全局的、靜態(tài)的大數(shù)組。

每個(gè)常量都在常量的字符串區(qū),直接一個(gè)指針把常量指向它的字符串就好了,沒(méi)有必要去數(shù)組里定義再拷貝過(guò)來(lái),除非需要經(jīng)常修改名字。如果名字是不變的,是恒定的一個(gè)常量,那就可以直接用第二種寫(xiě)法,第一種寫(xiě)法明顯是浪費(fèi)內(nèi)存,還有一個(gè)副作用是從性能角度來(lái)說(shuō),如果定義成一組大數(shù)組,第一種寫(xiě)法會(huì)導(dǎo)致內(nèi)存里的數(shù)據(jù)特別松散,訪問(wèn)不緊湊的數(shù)據(jù)會(huì)浪費(fèi)緩存。

現(xiàn)在我們用工具來(lái)測(cè)一測(cè),用這兩種寫(xiě)法來(lái)測(cè)量一下性能差別。FOO代表不好的寫(xiě)法,循環(huán)遍歷,根據(jù)id來(lái)搜索其中的一個(gè)元素;GOO代表好的寫(xiě)法。



測(cè)量有幾種模式,一種是用batch成批測(cè)量。我們做調(diào)優(yōu)的時(shí)候先循環(huán)跑幾次,根據(jù)開(kāi)始和結(jié)束的時(shí)間取平均值會(huì)比較準(zhǔn)。最后我們得到緊湊結(jié)構(gòu)體的速度要比松散結(jié)構(gòu)體快36%。

另一種是用Interlace模式測(cè)量,分批測(cè)量再分別統(tǒng)計(jì)數(shù)據(jù)。最后也可以看到34%左右的性能差距。但I(xiàn)nterlace模式測(cè)量的開(kāi)銷相對(duì)來(lái)說(shuō)比較大。

從內(nèi)存角度來(lái)說(shuō),如果用VTune專業(yè)工具來(lái)觀察,可以看到每一行語(yǔ)句的開(kāi)銷,也可以從中得出相同的結(jié)論,訪問(wèn)緊湊結(jié)構(gòu)的效果更好。而訪問(wèn)松散結(jié)構(gòu)則容易產(chǎn)生很多TLB miss。



什么是TLB miss?現(xiàn)代CPU的復(fù)雜機(jī)制,其一就是復(fù)雜內(nèi)存。訪問(wèn)內(nèi)存都是為了查頁(yè)表,由于軟件里用的是虛擬內(nèi)存,真正做后端訪問(wèn)的時(shí)候都要轉(zhuǎn)成物理內(nèi)存,轉(zhuǎn)的過(guò)程中要查頁(yè)表。頁(yè)表很復(fù)雜,為了提高頁(yè)表速度,CPU內(nèi)部都有專門(mén)開(kāi)頁(yè)表的TLB,有代碼的TLB,也有數(shù)據(jù)的TLB。訪問(wèn)松散的大數(shù)組產(chǎn)生很多TLB miss,因?yàn)樗稚⒃诤芏鄠€(gè)頁(yè)上,在訪問(wèn)這些陌生頁(yè)的時(shí)候它就不在TLB里。

從另一個(gè)指標(biāo)來(lái)看,訪問(wèn)松散結(jié)構(gòu)時(shí)L1 cache miss會(huì)比較多。CPU內(nèi)部有很多級(jí)緩存,如L1/L2/L3......總的來(lái)說(shuō),今天CPU與內(nèi)存之間的矛盾非常突出。當(dāng)我們?cè)谧龈哳l交易的時(shí)候,CPU調(diào)頻速度非???,但內(nèi)存速度上不去,而且每次訪問(wèn)內(nèi)存時(shí)采樣要十幾個(gè)tick的latency,內(nèi)存的壓力很大。所以松散結(jié)構(gòu)體不僅浪費(fèi)內(nèi)存,而且訪問(wèn)的效率很低。



4.訪問(wèn)內(nèi)存

再來(lái)看一個(gè)例子,訪問(wèn)內(nèi)存的時(shí)候,比如這樣一個(gè)二維矩陣,到底應(yīng)該按行做循環(huán),還是可以跳著來(lái)訪問(wèn)?


總結(jié)來(lái)說(shuō),隔行訪問(wèn)會(huì)導(dǎo)致比較多的cache miss,也會(huì)降低效率,讓CPU來(lái)不及做cache,有很大的Memory Bound miss??赡苁荓1不行,可能是L2不行,也可能是最末一級(jí)LLC不行。最末一級(jí)不行就要訪問(wèn)物理內(nèi)存,訪問(wèn)物理內(nèi)存可能達(dá)到微秒級(jí)別,由于內(nèi)存之間是有排隊(duì)的,一訪問(wèn)內(nèi)存,時(shí)間就不可控了。



如今我們進(jìn)入多核時(shí)代,而多核化加劇了CPU核心與內(nèi)存之間的壓力,讓CPU和內(nèi)存之間的這條公路變得非常擁堵。而蘋(píng)果M1核心技術(shù)最大的創(chuàng)新就在于釋放了內(nèi)存與CPU核之間的約束。


而我們要解決這個(gè)約束就是用cache,中間加緩存,一級(jí)一級(jí)加。馮·諾依曼架構(gòu)的精髓是把內(nèi)存提高到空前的地位,把內(nèi)存重要化。內(nèi)存重要化之后,無(wú)論是代碼和數(shù)據(jù)都要寄存內(nèi)存,CPU才能訪問(wèn)。有了這個(gè)機(jī)制后,CPU和內(nèi)存之間就有了非常緊密的約束。這就是今天馮·諾依曼架構(gòu)的最大矛盾。

對(duì)于優(yōu)化cache,要做循環(huán)交換來(lái)做編譯執(zhí)行,記錄時(shí)間,提升數(shù)量級(jí),合并循環(huán)減少cache miss,讓CPU有更高的cache命中率。用不好cache就是白白浪費(fèi)了CPU的寶貴資源。

要想寫(xiě)開(kāi)啟友好的代碼,第一原則就是遵守局部性原則。局部性原則就是讓結(jié)構(gòu)體緊湊,讓訪問(wèn)時(shí)間性和空間性都離得很近。第二是溫度原則,我們經(jīng)常訪問(wèn),它的溫度就高。


納秒級(jí)調(diào)優(yōu)的第一大挑戰(zhàn)就是常??床怀鲂Ч?,或者看到相反的效果。那我們?nèi)绾巫约鹤稣{(diào)優(yōu)實(shí)驗(yàn)?zāi)兀?/p>


納秒級(jí)調(diào)優(yōu)三大守則


第一守則:防止編譯器好心幫倒忙

去除干擾,防止編器誤解,增加輸出,防止編譯器好心做壞事。



第二守則:禁止CPU調(diào)頻

把CPU的Speed Step選項(xiàng)禁掉,鎖定頻率,因?yàn)镃PU的調(diào)頻幅度非常大,不鎖定頻率測(cè)出來(lái)的都是干擾,數(shù)據(jù)跳動(dòng)幅度特別大。

使用Vtune這樣的專業(yè)工具可以直接打開(kāi)CPU層面的計(jì)數(shù)器,可以測(cè)出更準(zhǔn)確的數(shù)據(jù)。



關(guān)于我們

2022年3月11-12日,「全球C++及系統(tǒng)軟件技術(shù)大會(huì)」將于上海隆重召開(kāi),“C++之父”Bjarne Stroustrup將發(fā)布主題演講。來(lái)自海內(nèi)外近40位專家將圍繞包括:現(xiàn)代C++、系統(tǒng)級(jí)軟件、架構(gòu)與設(shè)計(jì)演化、高性能與低時(shí)延、質(zhì)量與效能、工程與工具鏈、嵌入式開(kāi)發(fā)、分布式與網(wǎng)絡(luò)應(yīng)用 共8大主題,深度探討最佳工程實(shí)踐和前沿方法。大會(huì)官網(wǎng):www.cpp-summit.org


從納秒級(jí)優(yōu)化談CPU眼里的好代碼的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
杨浦区| 白银市| 藁城市| 南充市| 新晃| 台州市| 洞头县| 四川省| 咸宁市| 忻城县| 柏乡县| 绥化市| 滕州市| 武汉市| 永康市| 峨边| 千阳县| 和林格尔县| 龙山县| 黑龙江省| 乐山市| 宁海县| 柯坪县| 兰西县| 荔浦县| 新竹市| 连山| 佳木斯市| 应用必备| 江孜县| 鹿泉市| 枞阳县| 麟游县| 华宁县| 临夏县| 平谷区| 田林县| 广平县| 鹤峰县| 永仁县| 武平县|