控制危障(control hazard)
你正開車駛向一個岔路,但導航還沒講完「左轉」還是「直走」。為了不停下,你得在知道哪條對之前先押一條路——而若押錯了,就得倒回去、損失時間。控制危障就是處理器的岔路:一條分支指令決定下一條跑哪一條,但那個決定來不及在不靠猜的情況下提取下一條指令。
時序是這樣。像 beq x1, x2, target 這樣的條件分支在 IF 被提取,但它是否被採取——因而下一個要從哪個位址提取——要等到一兩階之後比較完成才知道。然而管線想每一個週期都提取一條新指令。所以在分支之後緊接的那幾個週期,機器已經提取了實體上排在它後面的指令,卻還不知道那些是否正確。若分支結果是採取,那些預先提取的指令就是錯的,必須丟棄——這叫清空(flush)——並改為提取正確的目標,代價就是已花掉的那些週期。
控制危障代價高,因為分支無所不在——迴圈、if 敘述、函式呼叫——常常每五六條指令就有一條。有三種對策。停頓:凍結提取直到分支解出(簡單,但每次分支都浪費週期)。延遲分支:一個老把戲,總是執行緊接分支後的那條指令,把浪費的槽變成有用的工作。以及主導現代的答案,分支預測:猜結果,沿猜測的路徑推測性提取,只在罕見的猜錯時清空。好的預測器正確率遠超九成,所以控制危障大多消失——直到一次誤測,代價是一次完整的管線清空。
一個迴圈:beq x1, x0, exit 決定要再繞一圈還是離開。當它還在 EX 比較時,管線已經假設不跳而提取了後面兩條指令。若分支其實是跳到 exit,那兩條就是錯的:清空它們,改從 exit 提取,付出浪費的週期。
分支的結果來得晚,所以緊接它之後提取的指令可能是錯的、需要清空——這就是控制危障。
分支預測是效能特性,不是正確性特性:猜錯永遠不會產生錯誤答案,因為誤測的指令會在提交前被清空。誤測的代價是損失的週期,不是損失的正確性。