有關CPU性能的更完整圖片,請參閱Agner Fog's microarchitecture guide and instruction tables。 (他的優化C++和優化彙編指南也非常出色)。請參閱x86標記wiki中的其他鏈接,尤其是英特爾優化手冊。
爲了分析代碼的短序列的示例,請參閱
延遲和吞吐量的單指令實際上不是足以讓爲使用的矢量指令的混合循環有用的圖片。這些數字不會告訴您哪些內在函數(asm指令)彼此競爭吞吐量資源(即它們是否需要相同的執行端口)。它們僅適用於超簡單循環,例如加載/做一件事/商店,或者例如將數組與_mm_add_ps
或_mm_add_epi32
相加。
您可以使用多個累加器來獲得更多instruction-level parallelism,但是您仍然只使用一個內在因素,因此您確實有足夠的信息來查看例如, Skylake之前的CPU只能支持每個時鐘一個_mm_add_ps
的吞吐量,而SKL可以在每個時鐘週期啓動兩個(每0.5c一個相反的吞吐量)。它可以在兩個完全流水線的FMA執行單元上運行ADDPS,而不是使用單個專用的FP-add單元,因此與Haswell(3c lat,每1c輸出一個)相比,吞吐量更好但延遲更差。
由於_mm_add_ps
在Skylake上的延遲時間爲4個週期,這意味着8個矢量FP添加操作可以立即執行。所以你需要8個獨立的矢量累加器(你在最後添加到彼此)來揭示這麼多的並行性。 (例如用8個獨立的__m256 sum0, sum1, ...
變量手動展開循環。編譯器驅動的展開(使用-funroll-loops -ffast-math
編譯)通常使用相同的寄存器,但循環開銷不是問題)。
這些數字也離開了英特爾CPU性能的第三大尺寸:融合域UOP吞吐量。大多數指令解碼爲單個uop,但有些解碼爲多個uops。 (尤其是SSE4.2字符串指令,如您提到的_mm_cmpestrc
:PCMPESTRI是Skylake上的8個uops)。即使在任何特定的執行端口上都沒有瓶頸,您仍然可以阻止前端將亂序內核控制在工作中的能力。英特爾Sandybridge系列CPU每個時鐘最多可以發佈4個融合域uops,實際上通常可以接近於其他瓶頸不會發生時的情況。 (請參閱Is performance reduced when executing loops whose uop count is not a multiple of processor width?以瞭解不同環路大小的一些有趣的最佳前端吞吐量測試。)由於加載/存儲指令使用與ALU指令不同的執行端口,因此這可能是數據在L1高速緩存中很熱時的瓶頸。
除非您查看編譯器生成的asm,否則您不會知道編譯器必須使用多少額外的MOVDQA指令才能在寄存器之間複製數據,以解決沒有AVX的情況下大多數指令會替換它們的第一條指令源寄存器與結果。 (即破壞性目的地)。您也不會從循環中的任何標量操作知道循環開銷。
我想我有潛伏期之間的差異有了深入瞭解和吞吐量
似乎你的猜測沒有什麼意義,所以你肯定失去了一些東西。
CPUs are pipelined,其中的執行單元也是如此。 A「完全流水線」執行單元可以開始一個新的操作每個週期(吞吐量=每時鐘一個)
(倒數)吞吐量是當沒有數據相關性迫使它等待,例如一個操作可以如何頻繁啓動該指令每7個週期一個。
延遲時間是一個操作的結果準備需要多長時間,並且通常只有當它是循環運行的依賴鏈的一部分時纔有意義。
如果循環的下一次迭代獨立於前一次操作,那麼亂序執行可能會「看到」足夠遠以在兩次迭代之間找到instruction-level parallelism並保持自己繁忙,這隻會影響吞吐量。
(未完全完成編輯工作,以後將這個整理起來。)
吞吐量= 7表示一個可以就每7個週期。延遲= 11意味着單個結果需要11個週期。因此,平均來說,在任何給定時間約1.5,並且不超過2.(雖然這是一個多uop指令,所以調度器可能由於某種原因最終將uops從更多指令交錯)。順便說一下,Haswell上的PCMPESTRI的Agner Fog數字與英特爾的數據不匹配。) –