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