0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

從上到下的系統(tǒng)架構(gòu)分析方法Intel PMU的詳細(xì)資料概述

Linux閱碼場 ? 來源:未知 ? 2019-03-24 09:55 ? 次閱讀

引言

現(xiàn)代 CPU 大多具有性能監(jiān)控單元(Performance Monitoring Unit, PMU),用于統(tǒng)計(jì)系統(tǒng)中發(fā)生的特定硬件事件,例如緩存未命中(Cache Miss)或者分支預(yù)測錯(cuò)誤(Branch Misprediction)等。同時(shí),多個(gè)事件可以結(jié)合計(jì)算出一些高級指標(biāo),例如每指令周期數(shù)(CPI),緩存命中率等。一個(gè)特定的微體系架構(gòu)可以通過 PMU 提供數(shù)百個(gè)事件。對于發(fā)現(xiàn)和解決特定的性能問題,我們很難從這數(shù)百個(gè)事件中挑選出那些真正有用的事件。 這需要我們深入了解微體系架構(gòu)的設(shè)計(jì)和 PMU 規(guī)范,才能從原始事件數(shù)據(jù)中獲取有用的信息。

自頂向下的微體系架構(gòu)分析方法(Top-Down Microarchitecture Analysis Method, TMAM)可以在亂序執(zhí)行的內(nèi)核中識別性能瓶頸,其通用的分層框架和技術(shù)可以應(yīng)用于許多亂序執(zhí)行的微體系架構(gòu)。TMAM 是基于事件的度量標(biāo)準(zhǔn)的分層組織,用于確定應(yīng)用程序中的主要性能瓶頸,顯示運(yùn)行應(yīng)用程序時(shí) CPU 流水線的使用情況。

概述

現(xiàn)代高性能 CPU 的流水線非常復(fù)雜。 一般來說,CPU 流水線在概念上分為兩部分,即前端(Front-end)和后端(Back-end)。Front-end 負(fù)責(zé)獲取程序代碼指令,并將其解碼為一個(gè)或多個(gè)稱為微操作(uOps)的底層硬件指令。uOps 被分配給 Back-end 進(jìn)行執(zhí)行,Back-end 負(fù)責(zé)監(jiān)控 uOp 的數(shù)據(jù)何時(shí)可用,并在可用的執(zhí)行單元中執(zhí)行 uOp。 uOp 執(zhí)行的完成稱為退役(Retirement),uOp 的執(zhí)行結(jié)果提交并反饋到>架構(gòu)狀態(tài)(CPU 寄存器或?qū)懟貎?nèi)存)。 通常情況下,大多數(shù) uOps 通過流水線正常執(zhí)行然后退役,但有時(shí)候投機(jī)執(zhí)行的 uOps 可能會(huì)在退役前被取消,例如在分支預(yù)測錯(cuò)誤的情況下。

在最近的英特爾微體系結(jié)構(gòu)上,流水線的 Front-end 每個(gè) CPU 周期(cycle)可以分配4個(gè) uOps ,而 Back-end 可以在每個(gè)周期中退役4個(gè) uOps。 流水線槽(pipeline slot)代表處理一個(gè) uOp 所需的硬件資源。 TMAM 假定對于每個(gè) CPU 核心,在每個(gè) CPU 周期內(nèi),有4個(gè) pipeline slot 可用,然后使用專門設(shè)計(jì)的 PMU 事件來測量這些 pipeline slot 的使用情況。在每個(gè) CPU 周期中,pipeline slot 可以是空的或者被 uOp 填充。 如果在一個(gè) CPU 周期內(nèi)某個(gè) pipeline slot 是空的,稱之為一次停頓(stall)。如果 CPU 經(jīng)常停頓,系統(tǒng)性能肯定是受到影響的。TMAM 的目標(biāo)就是確定系統(tǒng)性能問題的主要瓶頸。

下圖展示并總結(jié)了亂序執(zhí)行微體系架構(gòu)中自頂向下確定性能瓶頸的分類方法。這種自頂向下的分析框架的優(yōu)點(diǎn)是一種結(jié)構(gòu)化的方法,有選擇地探索可能的性能瓶頸區(qū)域。 帶有權(quán)重的層次化節(jié)點(diǎn),使得我們能夠?qū)⒎治龅闹攸c(diǎn)放在確實(shí)重要的問題上,同時(shí)無視那些不重要的問題。

例如,如果應(yīng)用程序性能受到指令提取問題的嚴(yán)重影響, TMAM 將它分類為 Front-end Bound 這個(gè)大類。 用戶或者工具可以向下探索并僅聚焦在 Front-end Bound 這個(gè)分類上,直到找到導(dǎo)致應(yīng)用程序性能瓶頸的直接原因或一類原因。

設(shè)計(jì)

Top Level

在最頂層,TMAM 將 pipeline slot 分為四個(gè)主要類別:

Front-end Bound

1Front-endBound表示pipeline的Front-end不足以供應(yīng)Back-end。

Front-end是pipeline的一部分,負(fù)責(zé)交付uOps給Back-end執(zhí)行。

Front-endBound進(jìn)一步分為FetchLatency(例如,ICacheorITLBmisses)

和FetchBandwidth(例如,sub-optimaldecoding)。

Back-end Bound

1Back-endBound表示由于缺乏接受執(zhí)行新操作所需的后端資源而導(dǎo)致

停頓的pipelineslot。它進(jìn)一步分為分為MemoryBound(由于內(nèi)存子系統(tǒng)造成的

執(zhí)行停頓)和CoreBound(執(zhí)行單元壓力ComputeBound或者缺少指令級并行ILP)。

Bad Speculation

1BadSpeculation表示由于分支預(yù)測錯(cuò)誤導(dǎo)致的pipelineslot被浪費(fèi),

主要包括(1)執(zhí)行最終被取消的uOps的pipelineslot,以及(2)由于從

先前的錯(cuò)誤猜測中恢復(fù)而導(dǎo)致阻塞的pipelineslot。

Retiring

1Retiring表示運(yùn)行有效uOp的pipelineslot。理想情況下,

我們希望看到所有的pipelineslot都能歸類到Retiring,

因?yàn)樗cIPC密切相關(guān)。盡管如此,高Retiring比率并不意味著沒有提升優(yōu)化的空間。

后兩者表示非停頓的 pipeline slot,前兩者表示停頓的 pipeline slot。 下圖描述了一個(gè)簡單的決策樹來展示向下分析的過程。如果一個(gè) pipeline slot 被某個(gè) uOp 使用,它將被分類為 Retiring 或 Bad Speculation,具體取決于它是否最終提交。如果 pipeline 的 Back-end 部分不能接受更多操作(也稱為 Back-end Stall),未使用的 pipeline slot 被分類為 Back-end Bound。Front-end Bound 則表示>在沒有 Back-end Stall 的情況下沒有操作(uOps)被分配執(zhí)行。

Front-end Bound

在許多情況下,F(xiàn)ront-end 指令帶寬可能會(huì)影響性能,特別是在高 IPC 的情況下。一些專用單元被引入,用來隱藏流水線 Fetch 指令延遲以及維持所需的帶寬,例如 Loop Stream Detector (LSD) 以及 Decoded I-cache (DSB)。

TMAM 進(jìn)一步將 Front-end Bound 劃分為延遲和帶寬兩個(gè)子類:

ICache miss 屬于 Fetch Latency 分類

指令解碼器的低效問題屬于 Fetch Bandwidth 分類

這些度量標(biāo)準(zhǔn)都是以自頂向下的方式定義的。Fetch Latency 表示任何原因?qū)е碌闹噶钐崛○囸I(沒有指令輸送)。我們所熟知的 icache and i-TLB miss 就屬于這個(gè)類別,但是并不局限于此。Branch Resteers 表示流水線刷新(pipeline flush)之后的指令提取延遲。pipeline flush 可能由一些清除狀態(tài)的事件引起,例如 branch misprediction 或者 memory nukes。Branch Resteers 與 Bad Speculation 密切相關(guān)。

Back-end Bound

Back-end Bound 分為 Memory Bound 和 Core Bound,通過在每個(gè)周期內(nèi)基于執(zhí)行單元的占用情況來分析 Back-end 停頓。為了達(dá)到盡可能大的 IPC,需要使得執(zhí)行單元保持繁忙。例如,在一個(gè)有4個(gè) slot 的機(jī)器中,如果在穩(wěn)定狀態(tài)下只能執(zhí)行三個(gè)或更少的 uOps,就不能達(dá)到最佳狀態(tài),即 IPC 等于4。這些次優(yōu)周期稱為 Execution Stalls。

Memory Bound

1MemoryBound對應(yīng)緩存和內(nèi)存子系統(tǒng)相關(guān)的ExecutionStalls。這些停頓通常表現(xiàn)為執(zhí)行單元在短時(shí)間內(nèi)饑餓,例如load操作沒有在緩存中命中。對于常見情況,內(nèi)存訪問的真正代價(jià)是調(diào)度程序沒有其他準(zhǔn)備好的uOps提供給執(zhí)行單元。后面的uOps可能正在等待進(jìn)行中的內(nèi)存訪問,或者依賴于其他未準(zhǔn)備好的uOps。23ExecutionStalls包含幾個(gè)子類,每個(gè)子類都與特定的高速緩存級別相關(guān)聯(lián),取決于各個(gè)高速緩存級別是否可以滿足所需的數(shù)據(jù)。在某些情況下,ExecutionStall可能會(huì)經(jīng)歷顯著的延遲,遠(yuǎn)遠(yuǎn)大于相應(yīng)緩存級別的標(biāo)準(zhǔn)延遲,即使沒有發(fā)生相應(yīng)的緩存未命中。例如,L1D高速緩存通常具有與ALU停頓相當(dāng)?shù)妮^短的延遲。然而在某些情況下,如load操作被阻塞,無法將數(shù)據(jù)從較早的store操作轉(zhuǎn)發(fā)(forward)到一個(gè)重疊地址,這個(gè)load負(fù)載可能會(huì)遭受較高的延遲,雖然最終能在L1D中命中。在這種情況下,in-flight的load操作將持續(xù)很長時(shí)間并且不會(huì)產(chǎn)生L1Dmiss。因此,這個(gè)問題屬于L1Bound子類。45此外,與store操作相關(guān)的ExecutionStalls都屬于StoresBound子類。由于內(nèi)存訪問順序要求,store操作被緩存并異步執(zhí)行。通常,store操作對性能影響很小,但不能完全忽視。TMAM將StoresBound定義為那些執(zhí)行端口利用率(executionportutilization)較低,以及存在大量需要消耗資源用來緩沖store操作的周期。67最后,TMAM在Ext.MemoryBound子類下使用了一個(gè)簡單的啟發(fā)式算法來區(qū)分MEMBandwidth和MEMLatency。該啟發(fā)式算法的主要根據(jù)是當(dāng)前有多少請求依賴從內(nèi)存中獲取的數(shù)據(jù)。每當(dāng)這類請求的占用率超過一個(gè)高閾值時(shí)(例如最大請求數(shù)的70%),TMAM將其標(biāo)記為可能受內(nèi)存帶寬的限制。其他部分都屬于內(nèi)存延遲子類。

Core Bound

1CoreBound對應(yīng)于執(zhí)行單元存在壓力或者程序中缺少指令級別并行(ILP)。Corebound的

停頓可能表現(xiàn)為較短的執(zhí)行饑餓周期或者執(zhí)行端口利用率不佳,這使得識別Corebound比較困難。

例如,一個(gè)長延遲的除法操作可能會(huì)序列化執(zhí)行,而服務(wù)于特定類型uOps的執(zhí)行端口上的壓力

可能表現(xiàn)為一個(gè)周期內(nèi)只有少量端口被使用。23CoreBound的問題一般可以通過更好的代碼生成來緩解。例如,一系列相關(guān)的算術(shù)

運(yùn)算將被標(biāo)記為CoreBound。編譯器可以通過更好的指令調(diào)度來緩解這種停頓。

矢量化(Vectorization)也可以緩解CoreBound的問題。

Bad Speculation

Bad Speculation 表示由于不正確的預(yù)測而浪費(fèi)的 pipeline slot,主要包括兩部分:

執(zhí)行了最終不會(huì)被提交的 uOps 的 slots

從錯(cuò)誤預(yù)測中恢復(fù)而導(dǎo)致流水線被阻塞的 slots

TMAM 的一個(gè)關(guān)鍵原則就是將 Bad Speculation 放在了最頂層, Bad Speculation 確定了受到錯(cuò)誤執(zhí)行路徑影響的工作負(fù)載的比例,并反過來決定了其他類別中觀察值的準(zhǔn)確性。TMAM 進(jìn)一步將 Bad Speculation 分類為 Branch Mispredict 和 Machine Clears,這兩種情況導(dǎo)致的問題和 pipeline flush 相像。Branch Mispredict 主要關(guān)注如何使程序控制流對分支預(yù)測更友好,Machine Clears 則主要指出一些異常情況,例如清除內(nèi)存排序機(jī)(memory ordering machine clears)或者自修改代碼(self modifying code)。

Retiring

理想情況下,我們希望看到所有的 slots 都被標(biāo)記為 Retiring 類別。盡管如此,Retiring 比例高并不意味著沒有更多的性能提升空間。諸如 Floating Point Assists (FP_ASSISTS) 的微指令(Microcode)序列通常會(huì)影響性能并且可以避免。這類情況被標(biāo)記為 MSROM 子類以便引起注意。

非矢量化(non-vectorized)代碼的高 Retiring 比值可能是進(jìn)行向量化(vectorization)代碼的一個(gè)重要提示。這樣做基本上可以讓更多的操作通過單指令 uOp 完成,從而提高性能。TMAM 進(jìn)一步將 Retiring->Base 子類劃分為 FP Arith,并區(qū)分標(biāo)量操作和矢量操作。

應(yīng)用/工具

pmu-tools 是 Adni Kleen 開發(fā)的開源工具包,針對 Intel CPU 提供友好的接口來訪問原始事件,并提供一些附加功能。toplev 是 pmu-tools 中的一個(gè)工具,在 Intel CPU 的 Linux perf 基礎(chǔ)上實(shí)現(xiàn)了 TMAM 方法。toplev 可以定位 CPU Bound 代碼的瓶頸,不能識別其他(Not bound by CPU)代碼的瓶頸。toplev 是一個(gè)計(jì)數(shù)工具,它使用 PMU 來計(jì)數(shù)事件。toplev 的一個(gè)典型使用場景是,用戶已經(jīng)根據(jù)一個(gè)標(biāo)>準(zhǔn)工具(例如 perf, sysprof, pyprof)進(jìn)行采樣,了解 hot code 的分布,但是你想知道為什么這部分代碼運(yùn)行很慢。

安裝

toplev 在 Linux 上運(yùn)行,需要安裝 perf 工具。toplev 還需要訪問 PMU,在 VM 中運(yùn)行時(shí)需要注意啟用這個(gè)特性。注意,toplev 需要禁用 NMI watchdog,并以 root 身份運(yùn)行。

1%gitclonehttps://github.com/andikleen/pmu-tools2%cdpmu-tools3%exportPATH=$PATH:`pwd`4%sudosysctl-p'kernel.nmi_watchdog=0'

確定 CPU Bound 任務(wù)

第一步是確定程序是否真的是 CPU Bound 型工作負(fù)載。toplev 只能幫助定位解決 CPU Bound 問題。如果瓶頸在其他地方,則必須使用其他方法。非 CPU 瓶頸可以是網(wǎng)絡(luò),磁盤IO,顯卡等。

選擇要計(jì)數(shù)的代碼

一般來說toplev測量整個(gè)系統(tǒng)的性能數(shù)據(jù);當(dāng)指定一個(gè)工作負(fù)載時(shí),toplev將在工作負(fù)載運(yùn)行的時(shí)間段內(nèi)測量整個(gè)系統(tǒng),這一點(diǎn)和perf的使用是類似的。

1%toplev.pymy-workload2或者3%toplev.pysleepXXX

讓我們衡量一個(gè)簡單的工作負(fù)載。這是一個(gè) bc 表達(dá)式,在作者電腦上運(yùn)行大約1秒(在大多數(shù)情況下,使用長時(shí)間運(yùn)行的工作負(fù)載可能會(huì)更好),使用第一層級(-lxxx 參數(shù)用來設(shè)定測量的最大層級)運(yùn)行以避免任何 PMU 計(jì)數(shù)器的多路復(fù)用。

1%toplev.py-l1bash-c'echo"7^199999"|bc>/dev/null' 2Willmeasurecompletesystem. 3Usinglevel1. 4... 5C0BADBad_Speculation:31.66% 6Thiscategoryreflectsslotswastedduetoincorrect 7speculations,whichincludeslotsusedtoallocateuopsthat 8donoteventuallygetretiredandslotsforwhichallocation 9wasblockedduetorecoveryfromearlierincorrect10speculation...11C1FEFrontend_Bound:42.46%12ThiscategoryreflectsslotswheretheFrontendofthe13processorundersuppliesitsBackend...14C1BEBackend_Bound:27.25%15Thiscategoryreflectsslotswherenouopsarebeing16deliveredduetoalackofrequiredresourcesforaccepting17moreuopsintheBackendofthepipeline...18C0-T0CPUutilization:0.00CPUs19NumberofCPUsused...20C0-T1CPUutilization:0.00CPUs21C1-T0CPUutilization:0.00CPUs22C1-T1CPUutilization:0.00CPUs

每當(dāng)首次打印層節(jié)點(diǎn)時(shí),toplev 都會(huì)打印一個(gè)描述。默認(rèn)情況下,它顯示一個(gè)簡短描述,長描述可以使用--long-desc來啟用。在之后的例子中,我們禁用描述以獲得較短的輸出。toplev 輸出中,一些值以 core 為單位,另一些則以 thread 為單位收集。多 socket 的情況下還會(huì)有 socket 分類。

上面的例子中,我們沒有將工作負(fù)載(bc)綁定到某個(gè) CPU,所以不清楚 C0 或 C1 的值是否相關(guān)。由于 bc 是單線程的,我們可以將它綁定到一個(gè)已知的 CPU 核心,并使用--core來過濾該核心上的輸出。

1%toplev.py--coreC0--no-desc-l1taskset-c0bash-c'echo"7^199999"|bc>/dev/null'2Willmeasurecompletesystem.3Usinglevel1.4...5C0BADBad_Speculation:33.29%6C0-T0CPUutilization:0.00CPUs7C0-T1CPUutilization:0.00CPUs

可以結(jié)合 taskset 綁定到更多的 CPU 進(jìn)行多線程工作,并將結(jié)果進(jìn)行過濾。結(jié)果顯示bc受限于 Bad Speculation?,F(xiàn)在我們可以選擇更多的節(jié)點(diǎn)并更詳細(xì)地分析問題。

如果已知工作負(fù)載是單線程的,并且系統(tǒng)當(dāng)前空閑,那么也可以顯式指定--single-thread選項(xiàng)來測量工作負(fù)載,而不是默認(rèn)測量整個(gè)系統(tǒng)

1%toplev.py--no-desc--single-threadbash-c'echo"7^199999"|bc>/dev/null'2..3BADBad_Speculation:32.65%4CPUutilization:0.00CPUs

程序在初始化階段的行為相比生命周期后期的行為有很大的差異。為了精確測量,跳過這個(gè)階段通常是有用的。這可以用-D xxx選項(xiàng)來完成,xxx是跳過的毫秒數(shù)(需要較新版本的 perf)。當(dāng)程序運(yùn)行時(shí)間足夠長時(shí),這通常是不需要的,但是它有助于提高小測試的精度。默認(rèn)情況下,toplev 同時(shí)測量內(nèi)核和用戶代碼。如果只對用戶代碼感興趣,則可以使用--user選項(xiàng)。這往往會(huì)減少測量噪聲,因?yàn)橹袛啾贿^濾掉了。還有一個(gè)--kernel選項(xiàng)用來測量內(nèi)核代碼。在具有多個(gè)階段的復(fù)雜工作負(fù)載上,測量間隔也是有用的。這可以用-I xxxi選項(xiàng)指定,xxx是間隔的毫秒數(shù)。perf 要求時(shí)間間隔至少需要 100ms。toplev 將輸出每個(gè)間隔的測量值。這往往會(huì)產(chǎn)生大量的數(shù)據(jù),所以繪制輸出很有必要。

選擇正確的層次和多路復(fù)用

PMU 只有有限數(shù)量的計(jì)數(shù)器可以同時(shí)測量事件。任何多于一個(gè)層次的 toplev 運(yùn)行,或者啟動(dòng)了額外的CPU 指標(biāo),則需要更多的計(jì)數(shù)器。在這種情況下,內(nèi)核驅(qū)動(dòng)程序?qū)㈤_始多路復(fù)用(Multiplexing),并定期更改事件組(在1毫秒和10毫秒之間,通常2.5毫秒,取決于內(nèi)核配置)。多路復(fù)用可能會(huì)導(dǎo)致測量錯(cuò)誤,因?yàn)?toplev 中的幾個(gè)節(jié)點(diǎn)中的公式需要關(guān)聯(lián)多個(gè)事件組的數(shù)據(jù)。因此 toplev 在反復(fù)執(zhí)行同樣事情的工作負(fù)載上效果最好,但在執(zhí)行許多不同的短事件的工作負(fù)載上效果不佳。

只要沒有使用 PMU 的或者有問題的其他工作負(fù)載處于活動(dòng)狀態(tài),則第一層次(-l1)和未啟用額外指標(biāo)的 toplev 不會(huì)進(jìn)行多路復(fù)用。一開始的時(shí)候,不采用多路復(fù)用來進(jìn)行分析通常是一個(gè)好主意。更高的層次和指標(biāo)提供了額外的信息,但也增加了復(fù)用,因此可能導(dǎo)致更多的測量錯(cuò)誤。如果工作負(fù)載非常重復(fù),可以使用--no-multiplex關(guān)閉復(fù)用。toplev 會(huì)根據(jù)需要多次重新運(yùn)行工作量。在 BIOS 中禁用超線程將使通用計(jì)數(shù)器的數(shù)量增加一倍,并減少多路復(fù)用。

有關(guān)問題的更多詳細(xì)信息和解決方法,可以參閱 reasons for measuring issues

數(shù)組求和實(shí)例的測試分析

我們考慮測量一些 beating the compiler 的例子。beating the compiler 實(shí)現(xiàn)了一個(gè)簡單的問題,即數(shù)組求和,從高級腳本語言開始,然后利用底層操作逐步優(yōu)化。測試代碼運(yùn)行在啟用了 Turbo 的 Intel Core i7-4600U(Haswell)筆記本電腦上。

開始是簡單直接的Python實(shí)現(xiàn)。

1defsum_naive_python():2result=03foriindata:4result+=i5returnresult

我們用 toplev 來運(yùn)行這段代碼,跳過初始化階段(大約80毫秒,通過預(yù)先測量得到)。一般來說,測量太短的程序是很困難的(太多的其他影響占主導(dǎo)地位)。在這種情況下,我們通過迭代5000次測試來調(diào)試程序運(yùn)行至少幾秒鐘。

1%toplev.py-D80-l1--no-desc--coreC0taskset-c0pythonfirst.pynumbers2..3C0FEFrontend_Bound:22.08%4C0RETRetiring:75.01%

所以 Python 是一點(diǎn) Front-end Bound,但是從 toplev 中沒有其他發(fā)現(xiàn)可見的問題。我們可以通過將層級提高到3來更仔細(xì)地分析 Front-end Bound。注意這可能有缺點(diǎn),因?yàn)樗鼤?huì)導(dǎo)致多路復(fù)用。在這種情況下,工作負(fù)載運(yùn)行時(shí)間越長越好(我們將基準(zhǔn)函數(shù)循環(huán)5000次)。

1%toplev.py-D80-l3--coreC0taskset-c0pythonfirst.pynumbers 2... 3C0FEFrontend_Bound:21.91% 4C0FEFrontend_Bound.Frontend_Bandwidth:15.91% 5C0FEFrontend_Bound.Frontend_Bandwidth.DSB:32.11% 6ThismetricrepresentsCorecyclesfractioninwhichCPUwas 7likelylimitedduetoDSB(decodeduopcache)fetch 8pipeline... 9C0RETRetiring:74.97%10C0RETRetiring.Base:74.88%

可以觀察到 Front-end Bound 是 DSB (decoded uop cache) fetch。具體描述被簡化了,可以使用--long-desc來查看更具體的描述。

讓我們來看看第二個(gè) Python 版本。這個(gè)版本使用 Python 中的內(nèi)建函數(shù) sum() 來數(shù)組求和,以便將更多的執(zhí)行動(dòng)作從解釋器推送到 Python C 核心。

1defsum_builtin_python():2returnsum(data)

在這種情況下,我們知道 python 代碼是單線程的(系統(tǒng)的其余部分是空閑的),所以可以使用--single-thread。

1%toplev.py--single-thread-l3-D80pythonsecond.pynumbers2...3FEFrontend_Bound:27.40%4FEFrontend_Bound.Frontend_Bandwidth:23.20%5FEFrontend_Bound.Frontend_Bandwidth.DSB:46.30%6ThismetricrepresentsCorecyclesfractioninwhichCPUwas7likelylimitedduetoDSB(decodeduopcache)fetch8pipeline...

然而這并沒有改變多少結(jié)果。Python 是相當(dāng)重(heavy-weight)的,大大加重了 CPU 的前端,但其中大部分至少在解碼的 icache 中運(yùn)行。

現(xiàn)在我們來看一個(gè)標(biāo)準(zhǔn)的C實(shí)現(xiàn),它應(yīng)該快得多:

1intsum_simple(int*vec,size_tvecsize)2{3intres=0;4inti;5for(i=0;i

這個(gè)循環(huán)被編譯成一個(gè)簡單的測試工具,使用 gcc 4.8.3 并關(guān)閉優(yōu)化,使用 toplev 進(jìn)行測量:

1%toplev.py-l1--single-thread--force-events./c1-unoptimizednumbers2BEBackend_Bound:60.34%3Thiscategoryreflectsslotswherenouopsarebeing4deliveredduetoalackofrequiredresourcesforaccepting5moreuopsintheBackendofthepipeline...

這個(gè)版本比 Python 版本運(yùn)行速度快4倍。瓶頸已經(jīng)完全進(jìn)入 Back-end。我們可以在第三層級更仔細(xì)地看待它:

1%toplev.py-l3--single-thread--force-events./c1-unoptimizednumbers 2BEBackend_Bound:60.42% 3BE/MemBackend_Bound.Memory_Bound:32.23% 4BE/MemBackend_Bound.Memory_Bound.L1_Bound:32.44% 5ThismetricrepresentshowoftenCPUwasstalledwithout 6missingtheL1datacache... 7Samplingevents:mem_load_uops_retired.l1_hit:pp,mem_load_uops_retired.hit_lfb:pp 8BE/CoreBackend_Bound.Core_Bound:45.93% 9BE/CoreBackend_Bound.Core_Bound.Ports_Utilization:45.93%10Thismetricrepresentscyclesfractionapplicationwas11stalledduetoCorecomputationissues(nondivider-12related)...

可以看到它是 L1 Bound 和 Core Bound。 L1 Bound 可能是因?yàn)槲磧?yōu)化的 gcc 代碼傾向于將所有變量存儲在堆棧上,沒有進(jìn)行全面的寄存器優(yōu)化。 我們可以用-O2打開優(yōu)化器,看看會(huì)發(fā)生什么:

1%toplev.py-l3--single-thread./c1-o2numbers2RETRetiring:83.66%3RETRetiring.Base:83.62%4ThismetricrepresentsslotsfractionwheretheCPUwas5retiringuopsnotoriginatedfromthemicrocode-sequencer...6Samplingevents:inst_retired.prec_dist:pp

L1 Bound 完全消失,工作負(fù)載的大部分時(shí)間都在 Retire,這是很好的。這個(gè)版本也比未優(yōu)化的C版本快了85%。注意這些好處有些極端的情況,可能完全取決于代碼的行為。

優(yōu)化 Retiring 的一種方法是對代碼進(jìn)行矢量化(Vectorization),并在每條指令上做更多的工作。通過gcc -O3啟用矢量化。不幸的是,它不能矢量化我們簡單的循環(huán)。

1c1.c:9:note:notvectorized:notsuitableforgatherload_32=*_31;

我們可以從 beating the compiler 中嘗試Roguelazer手動(dòng)優(yōu)化的內(nèi)嵌匯編 AVX2 版本。這應(yīng)該會(huì)減少 Retiring,因?yàn)樗诿總€(gè) SIMD 指令中可以執(zhí)行多達(dá)8個(gè)加法,同時(shí)它還使用了循環(huán)展開。

1%toplev.py-l3--single-thread./c-asmnumbers 2BEBackend_Bound:64.15% 3BE/MemBackend_Bound.Memory_Bound:... 4BE/MemBackend_Bound.Memory_Bound.L1_Bound:49.32% 5ThismetricrepresentshowoftenCPUwasstalledwithout 6missingtheL1datacache... 7Samplingevents:mem_load_uops_retired.l1_hit:pp,mem_load_uops_retired.hit_lfb:pp 8BE/MemBackend_Bound.Memory_Bound.L3_Bound:48.68% 9ThismetricrepresentshowoftenCPUwasstalledonL3cache10orcontendedwithasiblingCore...11Samplingevents:mem_load_uops_retired.l3_hit:pp12BE/CoreBackend_Bound.Core_Bound:28.27%13BE/CoreBackend_Bound.Core_Bound.Ports_Utilization:28.27%14Thismetricrepresentscyclesfractionapplicationwas15stalledduetoCorecomputationissues(nondivider-16related)...

Retiring 瓶頸已經(jīng)消失,我們終于看到了 Backend_Bound.Memory_Bound 瓶頸,在這種情況下,L1 Bound 和 L3 Bound所占百分比幾乎相等,其余的是核心執(zhí)行。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5268

    瀏覽量

    119646
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10769

    瀏覽量

    210425
  • PMU
    PMU
    +關(guān)注

    關(guān)注

    1

    文章

    107

    瀏覽量

    21533

原文標(biāo)題:從上到下的系統(tǒng)架構(gòu)分析方法 - Intel PMU

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    stm32 mini板子框體刷屏?xí)r框體本身明顯有從上到下的刷屏感覺

    ,顯示時(shí),框體上的控件是一次性顯示出來的,而框體本身明顯有從上到下的刷屏感覺,弄了幾天,也不知道問題出在哪里,還請高手相助,看看是什么原因。
    發(fā)表于 04-02 23:35

    萌新求助,求ARM內(nèi)核架構(gòu)和SOC架構(gòu)詳細(xì)資料

    萌新求助,求ARM內(nèi)核架構(gòu)和SOC架構(gòu)詳細(xì)資料
    發(fā)表于 10-25 06:12

    KeyStone處理器的硬件系統(tǒng)設(shè)計(jì)詳細(xì)資料概述

    本文的主要內(nèi)容介紹的是KeyStone處理器的硬件系統(tǒng)設(shè)計(jì)的詳細(xì)資料概述
    發(fā)表于 04-28 10:38 ?8次下載
    KeyStone處理器的硬件<b class='flag-5'>系統(tǒng)</b>設(shè)計(jì)<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    汽車控制電腦板的元件分析詳細(xì)資料概述

    本文檔的主要內(nèi)容介紹的 汽車控制電腦板的元件分析詳細(xì)資料概述內(nèi)容包括了:國產(chǎn)及大眾車系電腦,其它車系發(fā)動(dòng)機(jī)控制電腦,自動(dòng)變速器控制電腦,ABS控制模塊,電控空氣懸架系統(tǒng)模塊,自動(dòng)巡航
    發(fā)表于 06-08 08:00 ?53次下載
    汽車控制電腦板的元件<b class='flag-5'>分析</b>和<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    6SE70變頻器如何調(diào)試?及故障排除的方法詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是6SE70變頻器如何調(diào)試?及故障排除的方法詳細(xì)資料概述免費(fèi)下載。
    發(fā)表于 08-23 08:00 ?27次下載
    6SE70變頻器如何調(diào)試?及故障排除的<b class='flag-5'>方法</b><b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    數(shù)字系統(tǒng)設(shè)計(jì)與PLD應(yīng)用答案的詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是數(shù)字系統(tǒng)設(shè)計(jì)與PLD應(yīng)用答案的詳細(xì)資料概述
    發(fā)表于 10-22 16:48 ?7次下載
    數(shù)字<b class='flag-5'>系統(tǒng)</b>設(shè)計(jì)與PLD應(yīng)用答案的<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    EXC9000勵(lì)磁系統(tǒng)MODBUS通訊協(xié)議的詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是EXC9000勵(lì)磁系統(tǒng)MODBUS通訊協(xié)議的詳細(xì)資料概述
    發(fā)表于 10-24 08:00 ?1次下載
    EXC9000勵(lì)磁<b class='flag-5'>系統(tǒng)</b>MODBUS通訊協(xié)議的<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    組態(tài)王與數(shù)據(jù)庫連接的實(shí)現(xiàn)方法詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是組態(tài)王與數(shù)據(jù)庫連接的實(shí)現(xiàn)方法詳細(xì)資料概述。
    發(fā)表于 10-31 08:00 ?21次下載
    組態(tài)王與數(shù)據(jù)庫連接的實(shí)現(xiàn)<b class='flag-5'>方法</b><b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    單片機(jī)的電壓檢測系統(tǒng)的設(shè)計(jì)方法資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是單片機(jī)的電壓檢測系統(tǒng)的設(shè)計(jì)方法資料概述詳細(xì)資料免費(fèi)下載。
    發(fā)表于 11-12 08:00 ?25次下載
    單片機(jī)的電壓檢測<b class='flag-5'>系統(tǒng)</b>的設(shè)計(jì)<b class='flag-5'>方法</b><b class='flag-5'>資料</b><b class='flag-5'>概述</b>

    如何在Linux如何刪除大量文件的詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是如何在Linux刪除大量文件的過程詳細(xì)資料概述免費(fèi)下載。
    發(fā)表于 11-14 17:10 ?7次下載

    python的內(nèi)置函數(shù)詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是python的內(nèi)置函數(shù)詳細(xì)資料概述。
    發(fā)表于 11-18 08:00 ?0次下載

    新能源汽車的循環(huán)冷卻系統(tǒng)詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是新能源汽車的循環(huán)冷卻系統(tǒng)詳細(xì)資料概述。
    發(fā)表于 03-03 08:00 ?20次下載
    新能源汽車的循環(huán)冷卻<b class='flag-5'>系統(tǒng)</b>的<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    連續(xù)時(shí)間系統(tǒng)的時(shí)域分析詳細(xì)資料說明

    本文檔的主要內(nèi)容詳細(xì)介紹的是連續(xù)時(shí)間系統(tǒng)的時(shí)域分析詳細(xì)資料說明。
    發(fā)表于 03-06 08:00 ?0次下載
    連續(xù)時(shí)間<b class='flag-5'>系統(tǒng)</b>的時(shí)域<b class='flag-5'>分析</b>的<b class='flag-5'>詳細(xì)資料</b>說明

    EMC HF墊圈的詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是EMC HF墊圈的詳細(xì)資料概述免費(fèi)下載。
    發(fā)表于 09-07 08:00 ?0次下載
    EMC HF墊圈的<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>

    PLC控制系統(tǒng)的設(shè)計(jì)與應(yīng)用實(shí)例詳細(xì)資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是PLC控制系統(tǒng)的設(shè)計(jì)與應(yīng)用實(shí)例詳細(xì)資料概述包括了:1.PLC控制系統(tǒng)設(shè)計(jì)的內(nèi)容和步驟,2.PLC控制
    發(fā)表于 09-10 17:16 ?65次下載
    PLC控制<b class='flag-5'>系統(tǒng)</b>的設(shè)計(jì)與應(yīng)用實(shí)例<b class='flag-5'>詳細(xì)資料</b><b class='flag-5'>概述</b>