我想知道使用不覆寫整個線性地址空間的段描述符是否比使用那些更慢?
我希望速度沒有差異。
uj5u.com熱心網友回復:
從技術上講沒有:具有較小的限制并不慢 AFAIK。
但是在 Skylake 等現代主流 CPU 上,非零基數會使負載使用延遲增加 1 個周期。(即一個額外的地址生成周期。)CPU 硬體有一個樂觀的快速路徑,可以在正常情況下跳過該加法,即它為零,否則它是加載延遲的關鍵路徑的一部分。
這在諸如鏈表、(二叉樹)樹之類的指標追蹤場景中最為明顯,以及其他加載地址準備就緒是依賴于該加載的資料的關鍵路徑依賴鏈的一部分的情況。否則亂序的 exec 大多可以隱藏它。
對于 L1d 命中,現代 Intel CPU 上 GP-integer regs 的加載使用延遲是 5 個周期(零段基數),因此對于對此敏感的作業負載來說,額外的 1 個周期很重要。(或在某些 Intel CPU 上的指標追蹤用例中的 4 個周期(當基本 reg 本身來自負載時):有關其樂觀 TLB 的詳細資訊,請參閱當 base offset 位于與基本不同的頁面時是否有懲罰?使用基本 reg 查找而不是等待正確的 AGU 結果。但我認為他們為 Ice Lake 放棄了它,所以它總是 5 個周期。)
非零段基仍然用于執行緒本地存盤,因此 CPU 仍然支持它們而不會造成災難性的性能損失。 (例如,在某些情況下,不會像低于正常的 FP 值那樣捕獲微碼輔助。)但它確實會消耗一些性能。
請參閱 Agner Fog 的微架構指南 ( https://agner.org/optimize/ ),以及https://stackoverflow.com/tags/x86/info中的其他鏈接。我也認為英特爾的優化手冊提到了英特爾 CPU 的這一點;我沒有檢查過AMD的。
例如對于 AMD K8/K10,Agner 寫道:
AMD 手冊說,如果代碼段基數為零,則分支誤預測懲罰為 10 個時鐘周期,如果代碼段基數為非零,則為 12 個時鐘周期。在我的測量中,我發現最小的分支誤預測損失分別為 12 和 13 個時鐘周期。
并且回復:K8/K10 上的資料加載/存盤:
根據我的測量,如果段基數為零,則計算地址并從該地址讀取一級快取所需的時間為 3 個時鐘周期,如果段基數為非零,則為 4 個時鐘周期。現代作業系統使用分頁而不是分段來組織記憶體。因此,您可以假設在 32 位和 64 位作業系統中段基數為零(通過 FS 或 GS?? 訪問的執行緒資訊塊除外)。在保護模式和實模式下,段基數在 16 位系統中幾乎總是非零
在 Agner 的指南中,我實際上并沒有提到英特爾 CPU 的額外延遲,因為它與大多數現代用途無關。所以查看英特爾的優化指南。
如果您使用的是分段記憶體模型,您可能最終會偶爾使用分段覆寫前綴;一些 CPU 對可以有效解碼的單個指令的前綴數量有限制,但至少 32 位模式不會有 REX 前綴。 pmovzxbd xmm0, [es: eax]將使用 3 個前綴(2 個強制性作為 SSE4.1 指令的一部分,加上 ES)和一個轉義位元組,這對于早期的 Silvermont 系列來說是個問題(但我認為以后的低功耗內核不會)。在 32 位模式下,您沒有 REX 前綴,因此這有助于避免該限制。
Agner Fog 的微架構指南說,在大多數 CPU 上解碼段覆寫沒有特別的懲罰。
Also, Intel CPUs (Core 2, Nehalem, and Sandybridge-family at least) do seem to rename segment registers, so modifying them like mov es, eax doesn't have to serialize out-of-order exec. But it's still not cheap, like 10 fused-domain uops for the front-end on Skylake, with 18c throughput. (But can pipeline with writes to other segment regs). See Is a mov to a segmentation register slower than a mov to a general purpose register? for some more details and test results.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/434740.html
