linux power_评估Linux on POWER的性能
linux power
介紹
在現代機器上,應用程序性能評估可能是一項復雜的任務。 通用工具幾乎無法處理所有性能變量。 每個工作負載所強調的是不同的計算機子系統。 測量和調整CPU綁定程序與調整IO綁定或內存綁定程序有很大不同。 在本文中,我們重點介紹編譯語言環境(C,C ++和其他語言)中與CPU綁定和與內存綁定的程序。 我們演示如何:
- 查找程序熱點 (程序中執行的指令所占比例很高的區域,功能,方法)
- 使用處理器上可用的硬件性能計數器來測量程序在POWER7上的行為
- 確定用于Linux上性能評估的工具。
POWER7的CPI模型
了解應用程序性能分析始于CPI指標的討論。 每條指令的周期數(CPI)度量是完成一條指令所需的處理器周期數。 每條指令被分解為多個階段:經典的RISC管道將具有指令獲取階段,隨后是指令解碼/寄存器獲取,執行,可選的內存訪問以及最后的回寫。 CPU可以通過利用指令級并行性來提高其CPI度量(以較低的CPI值衡量):每個階段將在不同階段處理不同的指令。 優化時,請嘗試最小化CPI值以最大化系統利用率。 圖1顯示了流水線??處理器中的最佳指令流。
圖1.流水線處理器的最佳指令流
有時一個階段不能完全獨立于其他階段,或者它發出具有依賴性的指令,迫使處理器在繼續執行之前滿足該需求。 例如,緊隨算術指令的存儲器負載使處理器首先僅將數據提取到高速緩存或存儲器中,然后發出算術指令。 發生這種情況時,據說處理器管道會遇到停頓,從而使管道停頓。 圖2顯示了停滯的管道可能是什么樣子。
圖2.帶有停頓的流水線處理器
在圖1和圖2的示例中,請考慮在完全填充的流水線(每個周期完成一條指令)的11個操作周期內,處理器可以執行8條指令。 但是,當發生三個周期的停頓時,只有五個指令以相同的周期數執行。 性能損失約為40%。 根據算法的不同,某些停頓是不可避免的。 但是,仔細的分析可以提供有關如何重寫或調整某些代碼段以避免此類停頓的提示和建議。 在文章“現代微處理器-90分鐘指南”中找到了關于現代CPU流水線和指令級并行性的更完整和更生動的解釋(請參閱參考資料 )。
CPI細分模型(CBM)將功能處理器級與性能計數器相關聯,以顯示哪個CPU功能單元正在產生停頓。 CBM取決于CPU架構和處理器模型。 電源架構和英特爾架構具有完全不同的CBM。 盡管POWER5 CBM相似,但與POWER7 CBM不同。 圖3顯示了POWER7 CBM的一部分。 (請參閱此信息的文本版本 。)
圖3.部分POWER 7 CBM
在Power Architecture中,硬件性能計數器是一組專用寄存器,當處理器中發生特定事件時,其內容將更新。 POWER7處理器具有一個內置的性能監視單元(PMU),每個PMU具有六個線程級性能計數器監視程序(PCM)。 其中四個是可編程的,這意味著可以同時監視四個事件,并且可能有500多個性能事件。 POWER7性能計數器由組定義,并且PMU一次只能監視同一組的事件。 圖3顯示了用于定義POWER7 CBM的性能計數器的子集。 圖3中的計數器后面有一個配置文件,用于指示哪個CPU功能單元導致處理器停頓,并提供有關如何調整算法以消除它們的可能提示。
在圖3中 ,白框是在概要文件中監視的特定POWER7 PCM。 根據它們的值,計算出灰色框[每個框都標有星號(*)](這些指標沒有特定的硬件計數器)。
注:請在紙上,“綜合PMU事件參考POWER7”(見POWER7一個全面的PMU參考相關主題 )。
Linux上的工具
如何使用POWER7處理器中的PCM? 盡管您可以在POWER上使用各種分析方法,例如硬件中斷,代碼檢測(例如gprof),操作系統掛鉤(systemtap); PCM提供了一組廣泛的計數器,這些計數器可直接與處理器功能一起使用。 PCM探查器使用操作系統中斷以固定的時間間隔不斷采樣處理器寄存器的值。 盡管樣本分析可能導致比指令跟蹤結果更不精確的數字結果,但是它對整體系統性能的影響較小,并允許目標基準幾乎以全速運行。 結果數據不準確; 它是誤差容限的近似值。
對于PCM剖析Linux上的兩個最常用的工具是OProfile和perf (參見相關主題 )。 盡管兩者都使用相同的原理,并沿著工作負載的回溯不斷采樣特殊的硬件寄存器(通過syscall),但它們的配置和使用方式卻不同。
OProfile工具是適用于Linux系統的系統范圍的探查器,能夠以低開銷分析所有正在運行的代碼。 它由一個用于收集示例數據的內核驅動程序和守護程序以及一些用于將數據轉換為信息的后概要分析工具組成。 除非您需要帶注釋的源,否則不需要調試符號(gcc的-g選項)。 使用最新的Linux 2.6內核, OProfile可以提供gprof樣式的調用圖分析信息。 OProfile的典型開銷為1-8%,具體取決于采樣頻率和工作負載。
在POWER上, OProfile通過觀察性能硬件計數器和性能計數器的組來工作,盡管不同的組不能一起使用。 這意味著要從同一工作負載獲取不同的性能計數器,需要使用不同的OProfile事件配置多次運行它。 這也意味著您不能同時觀看整個POWER7 CBM。 可用的組在前面提到的“ POWER7 PMY詳細事件描述”文檔中定義,或者通過運行清單1中的命令來定義:
清單1. OProfile組清單
# opcontrol -l清單2中的命令演示了一個簡單的OProfile配置和調用:
清單2. OProfile POWER7 CPU周期配置
# opcontrol -l # opcontrol -–no-vmlinux # opcontrol -e PM_CYC_GRP1:500000 -e PM_INST_CMPL_GRP1:500000 -e PM_RUN_CYC_GRP1:500000 -e PM_RUN_INST_CMPL_GRP1:500000 # opcontrol --start運行清單3中的工作負載。
清單3. OProfile運行命令序列
# opcontrol --dump # opcontrol –-stop # opcontrol --shutdown要獲取性能計數器報告,請發出清單4中的命令:
清單4. OProfile報告生成
# opreport -l > workload_report注:請綜合指南OProfile developerWorks文章“識別性能瓶頸的OProfile適用于Linux on POWER”(見(雖然沒有更新的POWER7) 相關主題 )。
在Linux內核2.6.29中引入的perf工具可以分析硬件和軟件級別的性能事件。 該perf工具具有面向像OProfile的被程序導向的優勢,而不是系統。 它具有一些預設的性能計數器列表,例如“ cpu-cycles OR cycle”,“ branch-misses”或“ L1-icache-prefetch-misses”,并且能夠復用PMU組以允許收集多個性能計數器來自不同組的樣本,但同時會降低樣本精度。
一個缺點是,盡管它允許直接收集硬件性能計數器,但perf不能識別POWER7 CBM表示的計數器名稱。 它需要使用原始十六進制數字代替。 表1是OProfile事件到十六進制數字的映射,您可以將其與perf使用(使用記錄原始事件選項)以將CBM用于POWER7。
表1. POWER7性能事件原始代碼
| PM_RUN_CYC | 200f4 |
| PM_CMPLU_STALL | 4000A |
| PM_CMPLU_STALL_FXU | 20014 |
| PM_CMPLU_STALL_DIV | 40014 |
| PM_CMPLU_STALL_SCALAR | 40012 |
| PM_CMPLU_STALL_SCALAR_LONG | 20018 |
| PM_CMPLU_STALL_VECTOR | 2001年 |
| PM_CMPLU_STALL_VECTOR_LONG | 4004a |
| PM_CMPLU_STALL_LSU | 20012 |
| PM_CMPLU_STALL_REJECT | 40016 |
| PM_CMPLU_STALL_ERAT_MISS | 40018 |
| PM_CMPLU_STALL_DCACHE_MISS | 20016 |
| PM_CMPLU_STALL_STORE | 2004年 |
| PM_CMPLU_STALL_THRD | 1001c |
| PM_CMPLU_STALL_IFU | 4004c |
| PM_CMPLU_STALL_BRU | 4004e |
| PM_GCT_NOSLOT_CYC | 100f8 |
| PM_GCT_NOSLOT_IC_MISS | 2001年 |
| PM_GCT_NOSLOT_BR_MPRED | 4001a |
| PM_GCT_NOSLOT_BR_MPRED_IC_MISS | 4001c |
| PM_GRP_CMPL | 30004 |
| PM_1PLUS_PPC_CMPL | 100f2 |
注意 :在IBM Wiki“在POWER7系統上使用perf”中找到有關perf的全面指南(盡管POWER7尚未更新)(請參閱參考資料 )。
你可以得到與使用的原料代碼perf對應于中定義的POWER7事件OProfile從libpfm4項目(參見相關主題 ):它們在特定的POWER7頭(LIB /事件/ power7_events.h)定義。 示例程序examples / showevtinfo還顯示了事件名稱和相應的原始十六進制代碼。
為了獲得計數器信息,分析是一種常見的方法。 通過概要分析,開發人員可以識別代碼執行和數據訪問中的熱點,找到性能敏感的區域,了解內存訪問模式等。 在開始介紹之前,有必要制定一項績效評估策略。 該程序可能由各種模塊和/或動態共享對象(DSO)組成,可能會大量使用內核,它可能更多地取決于數據模式訪問(對L2或L3高速緩存訪??問的壓力很大),或者可能專注于向量操作單位。 下一節將重點介紹可能的績效評估策略。
績效評估策略
初步的性能評估是通過檢查CPU周期利用率計數器來找到程序熱點 。 要在POWER7上執行此操作,請觀看表2中列出的事件:
表2. POWER7 CPU周期利用率計數器
| PM_CYC | 處理器周期 |
| PM_INST_CMPL | 完成的PowerPC指令數 |
| PM_RUN_CYC | 由運行鎖存器控制的處理器周期。 操作系統使用運行鎖存器指示何時進行有用的工作。 運行鎖存器通常在OS空閑循環中清除。 通過運行鎖存器進行選通可以濾除空閑環路。 |
| PM_RUN_INST_CMPL | 完成的運行指令數 |
運行帶有這些事件的OProfile將顯示處理器花費在符號上的總時間。 下面是一個例子輪廓輸出用于從與IBM高級工具鏈5.0功率(見編譯SPECcpu2006基準套件的403.gcc部件相關主題 )。 以下是命令opreport -l的輸出。
清單5. 403.gcc基準測試的“ opreport-”輸出(計數器PM_CYC_GRP1和PM_INST_CMPL_GRP1)
CPU: ppc64 POWER7, speed 3550 MHz (estimated) Counted PM_CYC_GRP1 events ((Group 1 pm_utilization) Processor Cycles) with a unit mask of 0x00 (No unit mask) count 500000 Counted PM_INST_CMPL_GRP1 events ((Group 1 pm_utilization) Number of PowerPC Instructions that completed.) with a unit mask of 0x00 (No unit mask) count 500000 samples % samples % image name app name symbol name 204528 7.9112 32132 1.3848 gcc_base.none gcc_base.none reg_is_remote_cons\tant_p.isra.3.part.4 125218 4.8434 246710 10.6324 gcc_base.none gcc_base.none bitmap_operation 113190 4.3782 50950 2.1958 libc-2.13.so libc-2.13.so memset 90316 3.4934 22193 0.9564 gcc_base.none gcc_base.none compute_transp 89978 3.4804 11753 0.5065 vmlinux vmlinux .pseries_dedicated_\idle_sleep 88429 3.4204 130166 5.6097 gcc_base.none gcc_base.none bitmap_element_\allocate 67720 2.6194 41479 1.7876 gcc_base.none gcc_base.none ggc_set_mark 56613 2.1898 89418 3.8536 gcc_base.none gcc_base.none canon_rtx 53949 2.0868 6985 0.3010 gcc_base.none gcc_base.none delete_null_\pointer_checks 51587 1.9954 26000 1.1205 gcc_base.none gcc_base.none ggc_mark_rtx_\children_1 48050 1.8586 16086 0.6933 gcc_base.none gcc_base.none single_set_2 47115 1.8224 33772 1.4555 gcc_base.none gcc_base.none note_stores清單6. 403.gcc基準測試的“ opreport-”輸出(計數器PM_RUN_CYC_GRP1和PM_RUN_INST_CMPL_GRP1)
Counted PM_RUN_CYC_GRP1 events ((Group 1 pm_utilization) Processor Cycles gated by the run latch. Operating systems use the run latch to indicate when they are doing useful work. The run latch is typically cleared in the OS idle loop. Gating by the run latch filters out the idle loop.) with a unit mask of 0x00 (No unit mask) count 500000 Counted PM_RUN_INST_CMPL_GRP1 events ((Group 1 pm_utilization) Number of run instructions completed.) with a unit mask of 0x00 (No unit mask) count 500000 samples % samples % samples % app name symbol name 204538 8.3658 32078 1.3965 gcc_base.none gcc_base.none reg_is_remote_consta\nt_p.isra.3.part.4 124596 5.0961 252227 10.9809 gcc_base.none gcc_base.none bitmap_operation 112326 4.5943 50890 2.2155 libc-2.13.so libc-2.13.so memset 90312 3.6939 21882 0.9527 gcc_base.none gcc_base.none compute_transp 0 0 0 0 vmlinux vmlinux .pseries_dedicated\_idle_sleep 88894 3.6359 124831 5.4346 gcc_base.none gcc_base.none bitmap_element_all\ocate 67995 2.7811 41331 1.7994 gcc_base.none gcc_base.none ggc_set_mark 56460 2.3093 89484 3.8958 gcc_base.none gcc_base.none canon_rtx 54076 2.2118 6965 0.3032 gcc_base.none gcc_base.none delete_null_pointer\_checks 51228 2.0953 26057 1.1344 gcc_base.none gcc_base.none ggc_mark_rtx_childr\en_1 48057 1.9656 16005 0.6968 gcc_base.none gcc_base.none single_set_2 47160 1.9289 33766 1.4700 gcc_base.none gcc_base.none note_stores每個監視的事件在輸出中由一對列表示。 第一列顯示了從PCM中為指定事件收集的樣本數,第二列顯示了其在總樣本數中所占的百分比。 從該報告中可以看出,符號reg_is_remote_constant_p是消耗大多數處理器周期的符號,并且是代碼優化的理想選擇。 此配置文件僅標識哪些符號消耗最多的CPU周期,而不標識是否充分利用了處理器管線。 您可以通過比較計數器結果來調查管道利用率。
考慮計數器PM_INST_CMPL_GRP1 (第二對列); 符號bitmap_operation顯示的百分比高于reg_is_remote_constant_p符號。 對于每個完成的處理器指令,此性能計數器都會遞增,而PM_CYC_GRP1僅表示已利用的CPU周期數。 如果不做進一步分析,這可能表明符號reg_is_remote_constant_p比符號bitmap_operation包含更多的CPU停頓,因為為符號reg_is_remote_constant_p完成的指令數量明顯更少。 該配置文件提供了一個初步提示,指出哪個符號可用于后續的優化工作。
在開始研究并破解代碼之前,明智的做法是了解工作負載是否受CPU或內存限制。 這很重要,因為每種工作負載類型的優化方法都大不相同。 例如,大多數內存訪問來自高速緩存或主內存(與NUMA遠程節點內存訪問相反),而性能幾乎完全取決于所使用的算法和數據結構。 要研究內存訪問模式,請查看表3中的以下兩個性能計數器:
表3. POWER7內存利用率計數器
| PM_MEM0_RQ_DISP | 讀取分配給主內存的請求 |
| PM_MEM0_WQ_DISP | 寫分配給主內存的請求 |
這兩個計數器可以指示存儲器訪問模式是否主要來自存儲器讀取,寫入或兩者。 使用與之前相同的基準(來自SPECcpu2006的403.gcc ),該配置文件顯示:
清單7. 403.gcc基準測試的“ opreport-”輸出(計數器PM_MEM0_RQ_DISP和PM_MEM0_WQ_DISP)
CPU: ppc64 POWER7, speed 3550 MHz (estimated) Counted PM_MEM0_RQ_DISP_GRP59 events ((Group 59 pm_nest2) Nest events (MC0/MC1/PB/GX), Pair0 Bit1) with a unit mask of 0x00 (No unit mask) count 1000 Counted PM_MEM0_WQ_DISP_GRP59 events ((Group 59 pm_nest2) Nest events (MC0/MC1/PB/GX), Pair3 Bit1) with a unit mask of 0x00 (No unit mask) count 1000 samples % samples % app name symbol name 225841 25.8000 289 0.4086 gcc_base.none reg_is_remote_constant_p.\isra.3.part.4 90068 10.2893 2183 3.0862 gcc_base.none compute_transp 54038 6.1733 308 0.4354 gcc_base.none single_set_2 32660 3.7311 2006 2.8359 gcc_base.none delete_null_pointer_checks 26352 3.0104 1498 2.1178 gcc_base.none note_stores 21306 2.4340 1950 2.7568 vmlinux .pseries_dedicated_idle_sl\eep 18059 2.0631 9186 12.9865 libc-2.13.so memset 15867 1.8126 659 0.9316 gcc_base.none init_alias_analysis要觀察的另一套有趣的性能計數器是L2和L3對緩存的訪問壓力。 下面的示例使用perf來剖析SPECcpu2006 483.xalancbmk組件(見相關主題 )正在使用RHEL6.2 Linux系統GCC構建的。 該組件大量使用內存分配例程,因此會給內存子系統帶來很大壓力。 為此,請使用OProfile監視表4中的以下計數器:
表4. POWER7高速緩存/內存訪問計數器
| PM_DATA_FROM_L2 | 由于需求負載,已從本地L2重新加載了處理器的數據緩存 |
| PM_DATA_FROM_L3 | 由于需求負載,已從本地L3重新加載了處理器的數據緩存 |
| PM_DATA_FROM_LMEM | 處理器的數據緩存已從與該處理器位于同一模塊上的內存中重新加載 |
| PM_DATA_FROM_RMEM | 處理器的數據緩存是從與該處理器位于的模塊不同的內存中重新加載的 |
概要文件輸出顯示以下內容:
清單8. 489.Xalancbmk基準測試的“ opreport-”輸出(計數器PM_DATA_FROM_L2_GRP91和PM_DATA_FROM_L3_GRP91)
CPU: ppc64 POWER7, speed 3550 MHz (estimated) Counted PM_DATA_FROM_L2_GRP91 events ((Group 91 pm_dsource1) The processor's Data Cache was reloaded from the local L2 due to a demand load.) with a unit mask of 0x00 (No unitmask) count 1000 Counted PM_DATA_FROM_L3_GRP91 events ((Group 91 pm_dsource1) The processor's Data Cachewas reloaded from the local L3 due to a demand load.) with a unit mask of 0x00 (No unitmask) count 1000 samples % samples % image name app name symbol name 767827 25.5750 7581 0.2525 gcc_base.none gcc_base.none bitmap_element_allocate 377138 12.5618 8341 0.2778 gcc_base.none gcc_base.none bitmap_operation 93334 3.1088 3160 0.1052 gcc_base.none gcc_base.none bitmap_bit_p 70278 2.3408 5913 0.1969 libc-2.13.so libc-2.13.so _int_free 56851 1.8936 22874 0.7618 oprofile oprofile /oprofile 47570 1.5845 2881 0.0959 gcc_base.none gcc_base.none rehash_using_reg 41441 1.3803 8532 0.2841 libc-2.13.so libc-2.13.so _int_malloc清單9. 489.Xalancbmk基準測試的“ opreport-”輸出(計數器PM_DATA_FROM_LMEM_GRP91和PM_DATA_FROM_RMEM_GRP91)
Counted PM_DATA_FROM_LMEM_GRP91 events ((Group 91 pm_dsource1) The processor's Data Cache was reloaded from memory attached to the same module this proccessor is located on.) witha unit mask of 0x00 (No unit mask) count 1000 Counted PM_DATA_FROM_RMEM_GRP91 events ((Group 91 pm_dsource1) The processor's Data Cachewas reloaded from memory attached to a different module than this proccessor is located on.) with a unit mask of 0x00 (No unit mask) count 1000 samples % samples % image name app name symbol name 1605 0.3344 0 0 gcc_base.none gcc_base.none bitmap_element_allocate 1778 0.3704 0 0 gcc_base.none gcc_base.none bitmap_operation 1231 0.2564 0 0 gcc_base.none gcc_base.none bitmap_bit_p 205 0.0427 0 0 libc-2.13.so libc-2.13.so _int_free 583 0.1215 327 100.000 oprofile oprofile /oprofile 0 0 0 0 gcc_base.none gcc_base.none rehash_using_reg 225 0.0469 0 0 libc-2.13.so libc-2.13.so _int_malloc解釋概要文件輸出表明,大多數高速緩存壓力來自L2訪問,幾乎沒有需求的L3重載,因為L2訪問的總和相對計數器樣本值( PM_DATA_FROM_L2 )遠遠高于L3需求重載( PM_DATA_FROM_L3 )。 您只能通過更全面的分析(通過觀察更多的計數器)來獲取更多信息,例如L2訪問是否由于高速緩存未命中而導致CPU停頓。 從此示例配置文件可以得出的結論是,與高速緩存訪??問相比,主存儲器訪問( PM_DATA_FROM_LMEM事件)非常低,并且沒有遠程訪問(事件PM_DATA_FROM_RMEM ),表明沒有遠程NUMA節點存儲器訪問。 熱點和內存訪問模式的分析可以為優化工作提供指導; 在這種情況下,需要進行進一步分析以找出真正導致CPU停頓的原因,因為簡單地識別工作負載熱點和內存訪問模式不足以正確地識別CPU停頓。
為了提出更好的性能優化策略,需要使用perf工具而不是OProfile進行進一步分析,因為需要同時監視許多POWER7 CBM計數器( 圖3中所示的22個計數器),并提供更好的性能優化策略。 其中許多事件屬于不同的組,這意味著使用OProfile需要多次運行相同的工作負載。 該perf工具將復用硬件計數器的觀看時指定的柜臺都在不止一個組。 盡管這會導致結果的準確性降低,但總體結果往往與預期的結果非常相似,其優點是花了更少的分析時間。
以下示例使用perf來分析相同的SPECcpu2006 483.xalancbmk組件。 要分析此組件,請發出清單10中的命令:
清單10.用于生成POWER7 CBM的perf命令
$ /usr/bin/perf stat -C 0 -e r100f2,r4001a,r100f8,r4001c,r2001a,r200f4,r2004a,r4004a, r4004e,r4004c,r20016,r40018,r20012,r40016,r40012,r20018,r4000a,r2001c,r1001c,r20014, r40014,r30004 taskset -c 0 ./Xalan_base.none -v t5.xml xalanc.xsl > power7_cbm.dat此命令將使perf監視-c指定的CPU上-e參數定義的原始事件。 任務集調用可確保組件僅在0號CPU上運行。工作負載./Xalan_base.none -v t5.xml xalanc.xsl可以由另一個應用程序替換以進行概要分析。 配置文件完成后,perf命令將輸出一個簡單表,其中包含每個原始事件的總計數以及經過的秒數:
清單11. 489.Xalancbmk基準的“性能統計”輸出
Performance counter stats for 'taskset -c 0 ./Xalan_base.none -v t5.xml xalanc.xsl': 366,860,486,404 r100f2 [18.15%] 8,090,500,758 r4001a [13.65%] 50,655,176,004 r100f8 [ 9.13%] 11,358,043,420 r4001c [ 9.11%] 10,318,533,758 r2001a [13.68%] 1,301,183,175,870 r200f4 [18.22%] 2,150,935,303 r2004a [ 9.10%] 0 r4004a [13.65%] 211,224,577,427 r4004e [ 4.54%] 212,033,138,844 r4004c [ 4.54%] 264,721,636,705 r20016 [ 9.09%] 22,176,093,590 r40018 [ 9.11%] 510,728,741,936 r20012 [ 9.10%] 39,823,575,049 r40016 [ 9.07%] 7,219,335,816 r40012 [ 4.54%] 1,585,358 r20018 [ 9.08%] 882,639,601,431 r4000a [ 9.08%] 1,219,039,175 r2001c [ 9.08%] 3,107,304 r1001c [13.62%] 120,319,547,023 r20014 [ 9.09%] 50,684,413,751 r40014 [13.62%] 366,940,826,307 r30004 [18.16%] 461.057870036 seconds time elapsed為了分析perf靠在POWER7 CBM,提供了一種Python腳本輸出(檢查在power7_cbm.zip 可下載資源 ),其構成從所收集的虛擬和硬件計數器的計數器度量。 要創建報告,請發出清單12中的命令:
清單12. POWER7 CBM python腳本調用
$ power7_cbm.py power7_cbm.dat將輸出類似于清單13的輸出:
清單13. 489.Xalancbmk基準測試的“ power7_cbm.py”輸出
CPI Breakdown Model (Complete) Metric : Value : Percent PM_CMPLU_STALL_DIV : 49802421337.0 : 0.0 PM_CMPLU_STALL_FXU_OTHER : 67578558649.0 : 5.2 PM_CMPLU_STALL_SCALAR_LONG : 2011413.0 : 0.0 PM_CMPLU_STALL_SCALAR_OTHER : 7195240404.0 : 0.6 PM_CMPLU_STALL_VECTOR_LONG : 0.0 : 0.0 PM_CMPLU_STALL_VECTOR_OTHER : 1209603592.0 : 0.1 PM_CMPLU_STALL_ERAT_MISS : 22193968056.0 : 1.7 PM_CMPLU_STALL_REJECT_OTHER : 18190293594.0 : 1.4 PM_CMPLU_STALL_DCACHE_MISS : 261865838255.0 : 20.3 PM_CMPLU_STALL_STORE : 2001544985.0 : 0.2 PM_CMPLU_STALL_LSU_OTHER : 202313206181.0 : 15.7 PM_CMPLU_STALL_THRD : 2025705.0 : 0.0 PM_CMPLU_STALL_BRU : 208356542821.0 : 16.2 PM_CMPLU_STALL_IFU_OTHER : 2171796336.0 : 0.2 PM_CMPLU_STALL_OTHER : 30895294057.0 : 2.4 PM_GCT_NOSLOT_IC_MISS : 9805421042.0 : 0.8 PM_GCT_NOSLOT_BR_MPRED : 7823508357.0 : 0.6 PM_GCT_NOSLOT_BR_MPRED_IC_MISS : 11059314150.0 : 0.9 PM_GCT_EMPTY_OTHER : 20292049774.0 : 1.6 PM_1PLUS_PPC_CMPL : 365158978504.0 : 28.3 OVERHEAD_EXPANSION : 590057044.0 : 0.0 Total : 96.1該報告基于誤差范圍內的統計值,因此最終百分比并不完全準確。 即使具有很高的錯誤余量,也有大約20%的CPU停頓是由于數據高速緩存未命中( PM_CMPLU_STALL_DCACHE_MISS )。 最終指令完成百分比( PM_1PLUS_PPC_CMPL )約為28%。
未來的優化應該嘗試通過減少CPU停頓和/或GCT(全局完成表)百分比來最大化此數目。 根據此報告,另一種分析途徑是識別發生停頓的代碼。 為此,請使用perf record命令。 它將跟蹤原始計數器的性能,并創建一個帶有進程回溯的映射,從而可以識別哪個符號產生了最多的硬件事件。 這類似于OProfile工作方式。 在此示例中,要跟蹤PM_CMPLU_STALL_DCACHE_MISS事件,請發出清單14中的命令:
清單14. PM_CMPLU_STALL_DCACHE_MISS事件的性能記錄
$ /usr/bin/perf record -C 0 -e r20016 taskset -c 0 ./Xalan_base.none -v t5.xml xalanc.xslperf命令將使用結果創建一個數據文件(通常為“ perf.dat”)。 可以使用perf report命令以交互方式讀取它,如清單15所示 :
清單15. 489.Xalancbmk基準的“性能報告”的輸出
Events: 192 raw 0x2001639.58% Xalan_base.none Xalan_base.none [.] xercesc_2_5::ValueStore::contains 11.46% Xalan_base.none Xalan_base.none [.] xalanc_1_8::XStringCachedAllocator9.90% Xalan_base.none Xalan_base.none [.] xalanc_1_8::XStringCachedAllocator7.29% Xalan_base.none Xalan_base.none [.] xercesc_2_5::ValueStore::isDuplica5.21% Xalan_base.none libc-2.13.so [.] _int_malloc 5.21% Xalan_base.none Xalan_base.none [.] __gnu_cxx::__normal_iterator<xa4.17% Xalan_base.none libc-2.13.so [.] __GI___libc_malloc 2.08% Xalan_base.none libc-2.13.so [.] malloc_consolidate.part.4 1.56% Xalan_base.none Xalan_base.none [.] xalanc_1_8::ReusableArenaBlock<xa1.56% Xalan_base.none Xalan_base.none [.] xalanc_1_8::ReusableArenaBlock<xa1.04% Xalan_base.none libc-2.13.so [.] __free [...]通過使用POWER7 CBM計數器和性能報告工具進行的分析,您的優化工作可能會集中在優化符號xercesc_2_5 :: ValueStore :: contains(xercesc_2_5 :: FieldValueMap const *)上的內存和緩存訪問上。
此示例只是可能分析的一部分。 POWER7 CBM向您顯示,盡管顯示數據高速緩存停頓是造成CPU停頓的主要原因,但裝入和存儲單元( PM_CMPLU_STALL_LSU )和分支單元( PM_CMPLU_STALL_BRU )都是停頓的來源。 進一步的分析可以解決這些問題。
案例分析
以下案例研究應用了這些性能評估策略來分析三角數學函數的實現。 根據分析結果,將確定優化機會。 本案例研究中使用的函數是ISO C hypot函數,定義為直角三角形的斜邊的長度。 該功能由C99 POSIX.1-2001定義為:
double hypot(double x, double y); hypot()函數返回sqrt(x * x + y * y)。 成功時,此函數返回邊長為x和y的直角三角形的長度。 如果x或y是無窮大,則返回正無窮大。 如果x或y是NaN,而另一個參數不是無窮大,則返回NaN。 如果結果溢出,則會發生范圍錯誤,并且這些函數分別返回HUGE_VAL,HUGE_VALF或HUGE_VALL。 如果兩個參數都屬于非正規變量,并且結果均為非正規變量,則將發生范圍錯誤,并返回正確的結果。盡管該算法看起來很簡單,但是Infinity和NaN的浮點(FP)參數處理以及與FP操作相關的上溢/下溢給性能帶來了一些挑戰。 GNU C庫(參見相關主題 )提供了位于源樹在sysdeps / IEEE754 / DBL-64 / e_hypot.c hypot將的實現:
注意 :此代碼示例的許可證信息包含在附錄中 。
清單16.默認的GLIBC hypot源代碼
double __ieee754_hypot(double x, double y) { double a,b,t1,t2,y1,y2,w; int32_t j,k,ha,hb; GET_HIGH_WORD(ha,x); ha &= 0x7fffffff; GET_HIGH_WORD(hb,y); hb &= 0x7fffffff; if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} SET_HIGH_WORD(a,ha); /* a <- |a| */ SET_HIGH_WORD(b,hb); /* b <- |b| */ if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */ k=0; if(ha > 0x5f300000) { /* a>2**500 */ if(ha >= 0x7ff00000) { /* Inf or NaN */ u_int32_t low; w = a+b; /* for sNaN */ GET_LOW_WORD(low,a); if(((ha&0xfffff)|low)==0) w = a; GET_LOW_WORD(low,b); if(((hb^0x7ff00000)|low)==0) w = b; return w; } /* scale a and b by 2**-600 */ ha -= 0x25800000; hb -= 0x25800000; k += 600; SET_HIGH_WORD(a,ha); SET_HIGH_WORD(b,hb); } if(hb < 0x20b00000) { /* b < 2**-500 */ if(hb <= 0x000fffff) { /* subnormal b or 0 */ u_int32_t low; GET_LOW_WORD(low,b); if((hb|low)==0) return a; t1=0; SET_HIGH_WORD(t1,0x7fd00000); /* t1=2^1022 */ b *= t1; a *= t1; k -= 1022; } else { /* scale a and b by 2^600 */ ha += 0x25800000; /* a *= 2^600 */ hb += 0x25800000; /* b *= 2^600 */ k -= 600; SET_HIGH_WORD(a,ha); SET_HIGH_WORD(b,hb); } } /* medium size a and b */ w = a-b; if (w>b) { t1 = 0; SET_HIGH_WORD(t1,ha); t2 = a-t1; w = __ieee754_sqrt(t1*t1-(b*(-b)-t2*(a+t1))); } else { a = a+a; y1 = 0; SET_HIGH_WORD(y1,hb); y2 = b - y1; t1 = 0; SET_HIGH_WORD(t1,ha+0x00100000); t2 = a - t1; w = __ieee754_sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b))); } if(k!=0) { u_int32_t high; t1 = 1.0; GET_HIGH_WORD(high,t1); SET_HIGH_WORD(t1,high+(k<<20)); return t1*w; } else return w; }此實現非常復雜,主要是因為該算法執行了許多逐位FP到INT的轉換。 假定使用浮點指令比使用定點指令時某些FP操作(例如比較和乘法)的開銷更大。 在某些架構上確實如此,但在Power Architecture上卻不是。
評估此實現的第一步是創建一個可配置的基準。 在這種情況下,由于它只是一個帶有兩個參數的函數和一個簡單的算法(沒有內部函數調用或其他路徑),因此可以創建一個簡單的基準來對其進行評估(請參閱可下載資源中的hypot_bench.tar.gz)。 基準是績效評估的一部分; 優化應加快利用總工作負載性能的算法或算法的關鍵部分。 像這樣的綜合基準應該代表該功能的正常使用。 由于優化工作往往是資源和時間的浪費,因此需要將精力集中在最常見的使用情況或預期的行為上。 嘗試優化表示總程序使用率較低的代碼往往會浪費資源。
由于這是對單個功能的性能分析,因此您可以跳過熱點分析,而專注于CBM分析。 使用hypot_bench.c中的基準以及perf , 清單17中的CBM信息:
清單17.“ hypot”基準測試的“ power7_cbm.py”輸出
CPI Breakdown Model (Complete) Metric : Value : Percent PM_CMPLU_STALL_DIV : 8921688.0 : 8.7 PM_CMPLU_STALL_FXU_OTHER : 13953382275.0 : 5.0 PM_CMPLU_STALL_SCALAR_LONG : 24380128688.0 : 8.7 PM_CMPLU_STALL_SCALAR_OTHER : 33862492798.0 : 12.0 PM_CMPLU_STALL_VECTOR_LONG : 0.0 : 0.0 PM_CMPLU_STALL_VECTOR_OTHER : 275057010.0 : 0.1 PM_CMPLU_STALL_ERAT_MISS : 173439.0 : 0.0 PM_CMPLU_STALL_REJECT_OTHER : 902838.0 : 0.0 PM_CMPLU_STALL_DCACHE_MISS : 15200163.0 : 0.0 PM_CMPLU_STALL_STORE : 1837414.0 : 0.0 PM_CMPLU_STALL_LSU_OTHER : 94866270200.0 : 33.7 PM_CMPLU_STALL_THRD : 569036.0 : 0.0 PM_CMPLU_STALL_BRU : 10470012464.0 : 3.7 PM_CMPLU_STALL_IFU_OTHER : -73357562.0 : 0.0 PM_CMPLU_STALL_OTHER : 7140295432.0 : 2.5 PM_GCT_NOSLOT_IC_MISS : 3586554.0 : 0.0 PM_GCT_NOSLOT_BR_MPRED : 1008950510.0 : 0.4 PM_GCT_NOSLOT_BR_MPRED_IC_MISS : 795943.0 : 0.0 PM_GCT_EMPTY_OTHER : 42488384303.0 : 15.1 PM_1PLUS_PPC_CMPL : 53138626513.0 : 18.9 OVERHEAD_EXPANSION : 30852715.0 : 0.0 Total : 108.7概要分析表明,大多數CPU停止運行,因此性能損失來自加載和存儲單元( LSU-計數器PM_CMPLU_STALL_LSU_OTHER )。 LSU具有與之關聯的各種計數器,但是在CPU停頓分析期間,您的重點是與性能下降相關的計數器。 那些顯示POWER上的性能下降的原因與“加載-命中存儲(LHS)”危害相關。 當CPU將數據寫入一個地址,然后嘗試過快地再次加載該數據時,會發生很大的停頓。 下一步是通過首先檢查事件PM_LSU_REJECT_LHS (原始代碼“ rc8ac”)來檢查此特定算法是否發生這種情況,如清單18所示。
清單18. PM_LSU_REJECT_LHS POWER7事件的性能記錄
$ perf record -C 0 -e rc8ac taskset -c 0 ./hypot_bench_glibc $ perf report Events: 14K raw 0xc8ac79.19% hypot_bench_gli libm-2.12.so [.] __ieee754_hypot10.38% hypot_bench_gli libm-2.12.so [.] __hypot6.34% hypot_bench_gli libm-2.12.so [.] __GI___finite概要文件輸出顯示符號__ieee754_hypot是生成大多數PM_LSU_REJECT_LHS事件的符號。 研究由編譯器生成的匯編代碼,以識別哪些指令正在生成事件。 通過在性能perf report屏幕上進行迭代并選擇__ieee754_hypot符號,展開符號__ieee754_hypot來對程序集進行注釋,這將顯示清單19的輸出。
清單19. PM_LSU_REJECT_LHS POWER7事件的性能報告
: 00000080fc38b730 <.__ieee754_hypot>:0.00 : 80fc38b730: 7c 08 02 a6 mflr r00.00 : 80fc38b734: fb c1 ff f0 std r30,-16(r1)0.00 : 80fc38b738: fb e1 ff f8 std r31,-8(r1)13.62 : 80fc38b73c: f8 01 00 10 std r0,16(r1)0.00 : 80fc38b740: f8 21 ff 71 stdu r1,-144(r1)10.82 : 80fc38b744: d8 21 00 70 stfd f1,112(r1)0.23 : 80fc38b748: e9 21 00 70 ld r9,112(r1)17.54 : 80fc38b74c: d8 41 00 70 stfd f2,112(r1)0.00 : 80fc38b750: 79 29 00 62 rldicl r9,r9,32,330.00 : 80fc38b754: e9 61 00 70 ld r11,112(r1)0.00 : 80fc38b758: e8 01 00 70 ld r0,112(r1)8.46 : 80fc38b75c: d8 21 00 70 stfd f1,112(r1) [...]在代碼的早期,實現使用宏GET_HIGH_WORD將浮點數轉換為整數 ,以進行后繼按位運算。 GLIBC的math / math_private.h使用清單20中的代碼定義了宏。
清單20. GET_HIGH_WORD宏定義
#define GET_HIGH_WORD(i,d) \ do { \ieee_double_shape_type gh_u; \gh_u.value = (d); \(i) = gh_u.parts.msw; \ } while (0)導致LHS停頓的可能原因是該操作讀取float的內部值屬性,然后將其讀取到變量i 。 POWER7處理器沒有本機指令將浮點寄存器的內容逐位移動到定點寄存器。 在POWER上完成此操作的方法是使用存儲操作將FP編號存儲在浮點寄存器中的存儲器中,然后將相同的存儲器位置加載到定點(通用)中。 由于內存訪問比寄存器操作慢(即使在訪問L1數據高速緩存時),因此在存儲過程中CPU停頓以完成后續加載。
注 :文件, “POWER ISA 2.06(POWER7)”(見相關信息 ),包含更多的信息。
大多數情況下,性能計數器事件會觸發中斷,從而使指令的PC地址保存在與執行指令接近的位置。 這可能導致裝配注釋不完全準確。 為了減輕這種現象,POWER4和更高版本具有一組有限的性能計數器,它們的名稱為marked 。 標記的指令將在每個時間范圍內產生較少的事件; 但是,PC指令將準確無誤,從而產生準確的裝配注釋。 標記的事件在由opcontrol -l獲取的OProfile計數器列表中具有PM_MRK前綴。
要仔細檢查分析,請觀看PM_MRK_LSU_REJECT_LHS計數器。 PM_MRK_LSU_REJECT_LHS和PM_LSU_REJECT_LHS這兩個計數器都監視同一性能事件。 但是,標記的計數器( PM_MRK_LSU_REJECT_LHS )將在每個時間范圍內生成較少的事件,但具有更準確的程序集注釋。 (請參見清單21。 )
清單21. PM_MRK_LSU_REJECT_LHS POWER7事件的性能記錄
$ perf record -C 0 -e rd082 taskset -c 0 ./hypot_bench_glibc $ perf report Events: 256K raw 0xd08264.61% hypot_bench_gli libm-2.12.so [.] __ieee754_hypot35.33% hypot_bench_gli libm-2.12.so [.] __GI___finite這將在清單22中生成程序集批注。
清單22. PM_MRK_LSU_REJECT_LHS POWER7事件的性能報告
: 00000080fc38b730 <.__ieee754_hypot>: [...]1.23 : 80fc38b7a8: c9 a1 00 70 lfd f13,112(r1)0.00 : 80fc38b7ac: f8 01 00 70 std r0,112(r1)32.66 : 80fc38b7b0: c8 01 00 70 lfd f0,112(r1) [...]0.00 : 80fc38b954: f8 01 00 70 std r0,112(r1)0.00 : 80fc38b958: e8 0b 00 00 ld r0,0(r11)0.00 : 80fc38b95c: 79 00 00 0e rldimi r0,r8,32,061.72 : 80fc38b960: c9 61 00 70 lfd f11,112(r1 [...]清單23中 ,另一個符號顯示了35%的具有類似行為的已生成事件。
清單23.性能報告的更多亮點
: 00000080fc3a2610 <.__finitel>>0.00 : 80fc3a2610: d8 21 ff f0 stfd f1,-16(r1)100.00 : 80fc3a2614: e8 01 ff f0 ld r0,-16(r1)根據此信息,您的優化工作可能是通過除去FP到INT的轉換來消除這些停頓。 POWER處理器具有快速高效的浮點執行單元,因此無需使用定點指令執行這些計算。 POWER當前在GLIBC中使用的算法(sysdeps / powerpc / fpu / e_hypot.c)僅通過使用FP操作已刪除了所有LHS停頓。 結果是清單24中更簡單的算法。
清單24. PowerPC GLIBC hypot源代碼
double __ieee754_hypot (double x, double y) {x = fabs (x);y = fabs (y);TEST_INF_NAN (x, y);if (y > x){double t = x;x = y;y = t;}if (y == 0.0 || (x / y) > two60){return x + y;}if (x > two500){x *= twoM600;y *= twoM600;return __ieee754_sqrt (x * x + y * y) / twoM600;}if (y < twoM500){if (y <= pdnum){x *= two1022;y *= two1022;return __ieee754_sqrt (x * x + y * y) / two1022;}else{x *= two600;y *= two600;return __ieee754_sqrt (x * x + y * y) / two600;}}return __ieee754_sqrt (x * x + y * y); }TEST_INF_NAN宏是另一個較小的優化,它在開始進一步的FP操作之前測試數字是NaN還是INFINITY(這是由于對NaN和INFINITY進行的操作會引發FP異常,并且函數規范不允許這樣做)。 在POWER7上, isinf和isnan函數調用已由編譯器優化為FP指令,并且不會生成額外的函數調用,而在較舊的處理器(POWER6和較舊的處理器)上,它將生成對相應函數的調用。 優化基本上是相同的實現,但是內聯以避免函數調用。
最后,比較這兩種實現,執行以下簡單測試。 使用和不使用新算法重新編譯GLIBC,并比較每次基準測試的總時間。 清單25是默認的GLIBC實現結果:
清單25.帶有默認GLIBC假設的基準
$ /usr/bin/time ./hypot_bench_glibc INF_CASE : elapsed time: 14:994339 NAN_CASE : elapsed time: 14:707085 TWO60_CASE : elapsed time: 12:983906 TWO500_CASE : elapsed time: 10:589746 TWOM500_CASE : elapsed time: 11:215079 NORMAL_CASE : elapsed time: 15:325237 79.80user 0.01system 1:19.81elapsed 99%CPU (0avgtext+0avgdata 151552maxresident)k 0inputs+0outputs (0major+48minor)pagefaults 0swaps優化的版本結果如清單26所示 :
清單26.優化的GLIBC假設基準
$ /usr/bin/time ./hypot_bench_glibc INF_CASE : elapsed time: 4:667043 NAN_CASE : elapsed time: 5:100940 TWO60_CASE : elapsed time: 6:245313 TWO500_CASE : elapsed time: 4:838627 TWOM500_CASE : elapsed time: 8:946053 NORMAL_CASE : elapsed time: 6:245218 36.03user 0.00system 0:36.04elapsed 99%CPU (0avgtext+0avgdata 163840maxresident)k 0inputs+0outputs (0major+50minor)pagefaults 0swaps這是最終性能提高了100%以上,將基準時間縮短了一半。
結論
帶有硬件計數器配置文件的性能評估是一種功能強大的工具,可以了解工作負載在特定處理器上的行為方式,并提示在哪里進行性能優化。 最新的POWER7處理器具有數百個可用的性能計數器,因此我們提出了一個簡單的模型,該模型將工作負載映射到CPU停頓。 了解POWER7 CBM有點復雜,因此我們還介紹了簡化它的Linux工具。 性能評估的策略集中在如何查找熱點 ,如何理解應用程序的內存模式以及如何使用POWER7 CBM。 最后,我們使用了最近對GLIBC內的三角函數進行的優化來解釋用于生成優化代碼的性能分析。
附錄
根據GNU自由文檔許可版本1.3,已授予復制,分發和/或修改本文檔的權限; 沒有不變的部分,沒有前封面文字,也沒有后封面文字。
翻譯自: https://www.ibm.com/developerworks/opensource/library/l-evaluatelinuxonpower/index.html
linux power
總結
以上是生活随笔為你收集整理的linux power_评估Linux on POWER的性能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么各种年鉴都不公布
- 下一篇: [附源码]Java计算机毕业设计SSM高