3.4. 指令快取

並非只有處理器用到的資料有被快取;處理器執行的指令也會被快取。然而,這個快取比起資料快取,問題少了許多。有幾個理由:

  • 執行的程式碼的量取決於所需的程式碼大小。程式碼的大小一般視問題的複雜度而定。而問題的複雜度是固定的。
  • 程式的資料管理是由程式設計師所設計的,而程式的指令通常是由編譯器產生的。編譯器撰寫者知道產生良好程式的規則。
  • 程式流程比起資料存取模式更加能夠預測。現今的 CPU 非常擅於發現模式。這有助於預取。
  • 程式碼總是有相當好的空間與時間局部性。

有一些程式設計師應該遵循的規則,但這些主要都是如何使用工具的規則。我們將會在第六節討論它們。這裡我們僅討論指令快取的技術細節。

自從 CPU 核心時脈急遽增加、以及快取(即使是第一層快取)與核心之間的速度差距成長以來,CPU 便以管線來設計了。這表示一條指令的執行會分階段進行。一條指令會先被解碼、接著準備參數、最後再執行它。這種管線能夠非常長(以 Intel 的 Netburst 架構而言,> 20 個階段)。一條很長的管線意味著,若是管線延誤了(即,通過它的指令流被中斷了),它會花上一段時間才能恢復速度。管線拖延發生在––舉例來說––下一條指令的位置無法被正確地預測、或者載入下一條指令花了太長時間(如,當它必須從記憶體讀取的時候)的時候。

因此 CPU 設計者花費了大量的時間與晶片面積在分支預測上,以盡可能地降低管線延誤發生的頻率。

在 CISC 處理器上,解碼階段也會花上一些時間。x86 與 x86-64 處理器尤其受此影響。在最近幾年,這些處理器因而不在 L1i 上快取指令的原始位元組序列,而是快取被解碼的指令。在這種情況下的 L1i 被稱作「追蹤快取(trace cache)」。追蹤快取令處理器能夠在快取命中的情況下略過管線的前面幾步,這在管線被延誤時格外有效。

如同先前說過的,L2 的快取是包含程式碼與資料的統一式快取。在這裡,程式碼顯然是以位元組序列的形式被快取,而不是被解碼過的。

為了達到最好的效能,只有一些與指令快取相關的規則:

  1. 產生盡可能小的程式碼。有些例外,像是為了使用管線的軟體管線化(software pipelining)需要建立額外的程式碼的時候、以及使用小程式碼的間接成本太高之處。
  2. 協助處理器做出好的預取決策。這能夠通過程式佈局或是顯式的預取來做到。

這些規則通常由編譯器的程式碼產生(code generation)來強制執行。有一些程式設計師能做的事情,我們會在第六節討論它們。

results matching ""

    No results matching ""