(十九)冒險和預測,解決危險就能抓住機會
前面我們講到,流水線技術能夠顯著提高CPU的吞吐率,只不過我們需要解決結構冒險、數據冒險、控制冒險三個方面的問題,這些問題和CPU的運行機制密切相關。
一、結構冒險:
結構冒險問題本質是一個硬件資源搶佔的問題,也就是電路問題。同一個時鐘周期內,同時運行兩條計算機指令的不同階段的指令時,如果會恰好用到相同的電路,就產生了電路競爭的問題。下圖是一個典型的內存數據訪問的衝突問題:
由圖可見,第一條指令和第四條在同一個時鐘周期內前者執行訪問內存操作,後者執行了取指令操作,由於內存只有一個地址譯碼器作為地址輸入,因此沒辦法同時執行指令一和指令是的訪問內存操作。
類似這種「資源衝突」問題的解決方案其實只有一種,就是增加資源,我們可以將內存分為兩部分,一部分稱為「指令內存」,另一部分稱為「數據內存」,各自擁有譯碼器。這種將內存分為兩部分的方式稱為哈佛架構,但是它並不是馮·諾依曼體系的結構的方案,將內存分為指令內存和數據內存的方式固然能夠解決一部分資源衝突的問題,但它使得我們不能夠動態分配內存,喪失了靈活性。現代計算機體系在告訴緩存的設計上借鑒了這種架構,將高速緩存分為了指令緩存和數據緩存,如下圖:
由於CPU是從高速緩存讀取數據而不是直接讀取內存,因此,這種方式也就解決了數據訪問和指令訪問同時的資源衝突問題。
二、數據冒險:三種不同的依賴關係
和上述結構冒險問題不同的是,數據冒險的問題在於程序邏輯,當多個指令的執行相互之間有數據上的依賴關係,問題就產生了,主要是三種依賴關係:先寫後讀、先讀後寫、寫後再寫。
- 先寫後讀,程序中對一個變量對先寫入再讀取操作對應着不同的指令
- 先讀後寫,後續的指令對變量進行寫入,需要讀取前置指令賦值的變量的值
- 寫後再寫,變量的賦值先後順序需要保障,否則最終得到錯誤的值
三、解決數據冒險問題
由於在執行指令之前事先知道要訪問的寄存器和內存地址,因此可以判定其是否會觸發冒險,如會觸發則通過插入空指令NOP,什麼都不做,相當於讓CPU停頓一個時鐘周期這樣的方式來避免發生冒險。
四、總結
結構冒險,主要是由於並行指令使用系統的硬件電路所引發,通過增加硬件資源的方式可解決;
數據冒險,主要是由於不同指令執行所要操作的數據有交叉,為了指令執行的準確性,需要保障一定的執行順序,通過插入NOP指令解決。