我有一個 x86-64 Linux 程式,我試圖通過perf. 性能報告顯示最熱門的指令是帶有記憶體引數的從 double 到 long 的標量轉換,例如:
cvttsd2si (%rax, %rdi, 8), %rcx
這對應于 C 代碼,如:
extern double *array;
long val = (long)array[idx];
(這是一個不尋常的瓶頸,但代碼本身非常不尋常。)
為了通知優化,我想知道這些指令是否因為記憶體負載或算術轉換本身而變得很熱。回答這個問題的最佳方法是什么?我應該收集哪些其他資料,我應該如何進行優化?
有些東西我已經看過了。CPU 計數器結果顯示每條指令有 1.5% 的快取未命中:
30686845493287 cache-references
2140314044614 cache-misses # 6.975 % of all cache refs
52970546 page-faults
1244774326560850 instructions
194784478522820 branches
2573746947618 branch-misses # 1.32% of all branches
52970546 faults
自上而下的性能監視器顯示我們主要受后端約束:
frontend bound retiring bad speculation backend bound
10.1% 25.9% 4.5% 59.5%
Ad-hoc 測量top顯示所有 CPU 都固定在 100%,這表明我們沒有在等待記憶體。
最后一點值得注意:在 AWS EC2 上運行時,在內核數量相同的情況下,AMD 上的代碼比 Intel 上的代碼要慢得多(44%)。(在 Ice Lake 8375C 與 EPYC 7R13 上測驗)。什么可以解釋這種差異?
感謝您的任何幫助。
uj5u.com熱心網友回復:
為了通知優化,我想知道這些指令是否因為記憶體負載或算術轉換本身而變得很熱。回答這個問題的最佳方法是什么?
我認為這條指令很慢有兩個主要原因。1. 存在依賴鏈,該指令的延遲是一個問題,因為處理器正在等待它執行其他指令。2. 存在快取未命中(除非許多內核正在執行基于記憶體的操作,否則不可能用此類指令使記憶體飽和)。
首先,很難跟蹤特定指令上發生的事情(特別是如果指令沒有長時間執行)。您需要使用精確事件來跟蹤問題的根源,即可以使用導致事件的確切指令地址的事件。所有事件中只有一個(小)子集是精確的。
關于 (1),指令的延遲在兩種架構上都應該是大約 12 個周期(雖然它在 AMD 處理器上可能會稍微多一些,但我預計不會有 44% 的差異)。目標處理器能夠在給定的周期內同時執行多條指令。指令在不同的埠上執行并且也是流水線的。埠使用對于了解正在發生的事情很重要。這意味著熱回圈中的所有指令都很重要。您無法隔離此特定指令。現代處理器例外復雜,因此基本分析可能很棘手。UOPS_DISPATCHED.PORT_XXX在 Ice Lake 處理器上,您可以使用where XXXcan be 0, 1, 2_3, 4_9, 5, 6,等事件測量平均埠使用情況7_8. 該指令只有前三個重要。這些EXE_ACTIVITY.XXX事件也可能有用。您應該檢查一個埠是否飽和以及哪個埠。AFAIK,這些事件都不是精確的,因此您只能分析代碼塊(通常是熱回圈)。在 Zen 3 上,埠是FP23和FP45。IDK 這個架構上有哪些有用的事件(我不是很熟悉)。
在 Ice Lake 上,您可以檢查FRONTEND_RETIRED.LATENCY_GE_XXXXXX 是 2 整數冪的事件(應該是精確的,以便您可以查看該指令是否是影響事件的指令)。這有助于您了解前端還是后端是限制因素。
關于 (2),您可以檢查記憶體訪問的延遲以及 L1/L2/L3 快取命中/未命中的數量。在 Ice Lake 上,您可以使用MEM_LOAD_RETIRED.XXXwhere can be 等事件,XXX例如L1_MISS L1_HIT、L2_MISS、和。仍然在 Ice Lake 上,t 可能有助于跟蹤記憶體操作的延遲,其中再次是兩個整數的冪。L2_HITL3_MISSL3_HITMEM_TRANS_RETIRED.LOAD_LATENCY_GT_XXXXXX
您還可以使用 LLVM-MCA 在目標架構上靜態模擬回圈指令的調度(不考慮分支)。這對于深入了解調度程式可以輕松完成的作業非常有用。
什么可以解釋這種差異?
延遲和互惠吞吐量在兩個平臺上應該大致相同或至少接近。話雖如此,對于相同的核心數量,兩者肯定不會以相同的頻率運行。如果這不是來自那個,那么我懷疑這條指令實際上是一個問題(棘手的調度問題、錯誤/不準確的分析結果等)。
CPU 計數器結果顯示每條指令有 1.5% 的快取未命中
事情是這個cache-misses事件在這里肯定不是很豐富。實際上,它參考了最后一級快取 (L3) misses。因此,它沒有提供有關 L1/L2 未命中的任何資訊(以前的事件有)。
我應該如何著手優化呢?
如果代碼受延遲限制,解決方案是首先打破此回圈中的任何依賴鏈。展開回圈并對其進行重寫以使其對 SIMD 更友好可以極大地提高性能(該指令的倒數吞吐量約為 1 個周期,而延遲為 12 個周期,因此在這種情況下還有改進的余地) .
如果代碼受記憶體限制,那么您應該關心資料區域性。如果可能,資料應該適合 L1 快取。有很多技巧可以做到這一點,但如果沒有更多的背景關系,很難指導你。這包括例如排序資料、重新排序回圈迭代、使用較小的資料型別。
可能發生奇怪的例外意外行為的可能來源有很多。如果發生這樣的事情,那么如果不執行確切的代碼,幾乎不可能理解發生了什么。在這種情況下,所有細節都很重要。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/519853.html
