MIPS--cache管理

http://hi.baidu.com/qq520131714/blog/item/0f6adafefa7058365c600898.html

 

 

MIPS--cache管理

 

沒有Cache的MIPSCPU不能稱爲真正的RISC。可能這樣說不公平。但爲了一些特殊的目的,你可以設計一個含有小而緊密內存的MIPSCPU,而這些內存只需要固定個數的流水線步驟(最好是一個)就可以被訪問到。但絕大部分MIPS CPU都是含有cache的。
這一章將介紹MIPS的cache怎樣工作和軟件應該怎麼做才能使它可以被使用而且是可靠的。MIPSCPU重新啓動後,cache的狀態是不確定的,所以軟件必須非常小心。你有一些線索知道cache的大小(如果你直接知道cache的大小後去初始化,這是一個不好的軟件習慣。)。對於診斷程序員,我們將討論怎樣測試cache和獲取特殊入口。
對於實時應用程序的程序員,希望在CPU運行時能夠正確地控制cache。我們也將討論怎麼做,雖然我對使用一些竅門方式有懷疑。
當然這些也隨着MIPSCPU的發展而進步。對於早期的32位MIPS處理器,初始化cache或者使其無效,首先讓cache進入一種特殊的狀態,然後通過普通的讀寫操作來完成。對於後來的處理器,一些特殊的指令被定義出來做這些相關的操作。

4.1 cache和cache的管理
cache的工作就是將內存中的一部分數據在cache中保留一個備份,使這些數據能一個固定的極短的時間內被快速的存取並返回給CPU,這樣能保證流水線的連續運行。
絕大部分MIPSCPU針對指令和數據有其各自的cache(分別稱爲Icache和Dcache),這樣讀一條指令和一個數據的讀操作或者寫操作就能同時發生。
老的CPU家族(象x86)爲了保證被寫入CPU的代碼的一致性,所以沒有cache。現在的x86芯片擁有更靈活的硬件設計,從而保證軟件沒有必要從更本上了解cache(如果你正在裝一臺機器跑MS/DOS,它將在本質上提供一致性)。
但因爲MIPS機器有各自的cache,所以就沒有必要那麼靈活。cache對於應用程序來說必須是透明的,除了除了能感覺到運行速度的增加。但對於系統程序或者驅動程序,擁有cache的MIPSCPU並沒有嘗試cache對它們也是透明的。cache僅僅使CPU跑得更快,而不能給系統程序員有所幫助。在象Unix一類的操作系統中,操作系統能對應用程序完全隱藏cache,當然對於更多不能的勝任的操作系統,其也能很好的隱藏大部分cache的處理,但你可能必須知道在什麼時候需要調用適當的子程序來對cache做一些必要操作。

4.2 cache怎樣工作
從概念上講,cache是一個相連內存(associative memory),當數據被寫入時用數據的一部分作爲關鍵字來標誌的一塊存儲區域。在cache中,關鍵字是整個內存的地址。提供一個相同的關鍵字給相連內存,你將得到相同的數據。一個真實的相連內存在存入條目時,將完全按照它們的關鍵字,除非它已經滿了。然而,由於需要這個當前的關鍵字必須和所有被存的關鍵字同時比較,因此任何大小的真實相連內存不是效率低或速度慢,或者就是兩者都有。
怎樣我們才能設計有用的高速緩存,使其不僅效率高而且速度快呢?圖4.1展示了一種最簡單高速緩存的基本設計方案,直接映射(direct-mapped)高速緩存。它被1992年以前的MIPSCPU廣泛使用。
直接映射cache由許多塊簡單的高速緩存排列構成(通常每一塊稱之爲一line),通過地址低位在整個範圍內做索引。cache的每一條line都包含一個字或者幾個字的數據和一個標籤(tag)區域,tag記錄着數據所在內存的地址。
當一個讀操作時,每一條line都可以被訪問到,tag將和內存地址的高位做比較;如果匹配的話,我們知道是找到正確的數據了,這被稱之爲命中(hit)。如果在這一塊中有超過一個字的數據,對應的那個字的數據通過地址的最低幾位來選擇出來。
如果tag沒有匹配,這稱之爲沒有命中(miss),那麼數據需要從內存中讀入,然後複製到cache對應的line中。這對應line中原來的數據將會被拋棄,如果CPU又需要被拋棄的數據時,需要再次從內存中取得。
這樣的直接映射cache有一個特徵,就是對於任何一個內存地址,在高速緩存中只有唯一的一條line可以用來保存其數據。這樣有好處也有壞處。好處就是這樣的架構簡單,可以使CPU跑得更快。但簡單也有其不好的一面:如果你的程序要不停地交替使用兩個數據,而它們剛好要對應高速緩存中的同一塊(可能是它們對應內存地址的低位剛好一樣),這樣這兩個數據就會不停的將對方替換出高速緩存,以至高速緩存的效率被徹底的降下來。
而真正的相連內存將不會遇到這樣的折騰,但對於任何合理大小,它將是難以想象的複雜、昂貴和速度緩慢。
折衷的辦法就是使用two-way set-associative cache,其實就是兩個direct-mapped cache並聯,在它們中同時匹配內存位置。如圖4.2。這時對應一個地址將有兩次機會命中。Four-way set-associative cache (就是有四個直接映射的子高速緩存)在cache的設計中也是很平常的。但是這是有懲罰的。一個set-associate cache比起直接映射cache來需要更多的總線連接,所以cache太大以至於很難在一塊芯片上構造直接映射。
不過也有巧妙的地方,由於直接映射cache對於你需要的數據只有唯一的候選者,所以把一些東西放到tag匹配前運行是可能的(只要CPU不做和着個數據有關的操作)。這樣可以提高每一個時鐘利用率。
由於當運行一段時間後cache會被裝滿,所以當再次存放從內存讀來的數據時,就會拋棄一些cache內原有的數據。如果你知道這些數據在cache和內存中是一致的,那麼你可以直接把cache中的備份拋棄;但如果cache中的數據更新的話,你就需要首先把這些數據存回到內存中。
這就給我們帶來一個問題,cache怎樣處理寫操作?

4.3 Write-Through Caches in Early MIPS CPUs
CPU不能僅僅是讀數據(就象上面的討論),它們也要寫數據。由於cache只是將主存中的一部分數據做一個備份,所以有一個顯而易見的方法來處理CPU的寫操作,被稱之爲Write-Through cache。
對於Write-Through cache,寫操作時CPU總是將數據直接寫到主存中去;如果對應主存位置的數據在cache中有一個備份,那麼cache中的那個備份也要被更新。如果我們總是這樣做的,那麼cache中的任何數據將和主存中的保持一致,所以只要我們需要我們就可以拋棄任何一條cahce line的數據,並且除了消耗時間不會丟失任何東西。
當然這也是有危險的,當我們讓處理器等待寫操作結束時,處理器的運行速度將徹底的降下來,不過我們能修復這個問題。可以將要寫入主存的數據及其地址先保存在另一邊,然後有主存控制器自己取得這些數據並完成寫操作。這個臨時保存寫操作內容的地方被稱之爲寫操作緩衝區 (write buffer),它是先入先出的(FIFO)。
早期的MIPS CPU有一個直接映射的write-through cache和一個寫操作緩衝區,還有一個R3000的激發設置。它在同一芯片上構造cache控制器,但需要額外的高速存貯器芯片來存貯tag和數據。只有CPU跑一些特殊的程序很平均地產生的寫操作,主存系統在這種工作方式下才能很好的消化這些寫操作並工作的很好。
但CPU運行速度的增長比存貯器塊得多。某些時候當32位的MIPS讓位給64位R4000後,MIPS的速度就已經超過存貯器系統可以合理消化所有寫操作的臨界點了。

4.4 Write-Bach Cache in Recent MIPS CPUs
早期的MIPS CPU 使用簡單的write-through cache。後來的MIPS CPU由於速度太快而不能適用這種方法,它們會陷入存儲系統的寫操作中,速度慢得像爬行。
解決的方法就是把要寫的數據保留在cache中。要寫的數據只寫到cache中,並且對應的那條cahce line要做一個標記,使我們肯定不會忘記在某個時候把它回寫到內存中(一條line需要回寫,稱之爲dirty)。
Write-back cache還可以分成幾種不同的子處理方式。如果當前cache中沒有要寫地址所對應的數據,我們可以直接寫到主存中而不管cache,或者可以用特殊的方式把數據讀入cache,然後再直接寫cache,後面這種方式被稱之爲寫分配(write allocate)。用一種自私的觀點來看一個程序運行在一個CPU上,寫分配(write-allocate)看起來象浪費時間;但是它可以使整個系統的設計變得簡單,因爲在程序運行時讀寫內存都讀或者寫都是以一條cache line大小爲單位的塊進行操作。
從MIPS R4000 開始,MIPS CPU在芯片內擁有cache,而且都支持write-through和write-allocate兩種工作模式,line的大小也是支持16byte和32byte兩種。
MIPS cache的這些工作模式可以被應用到使用sillicon Graphics設計R4000和其他大型CPU,其他計算機系統也因爲多處理器系統而被這些cache工作模式影響到。

4.5 Cache設計的其他選擇
在上個世紀八十和九十年代針對怎樣設計cache,做了很多工作和研究。所以下面還有許多其它的設計選擇。
Physically addressed/virtually addressed:
當CPU在運行成熟的操作系統時,數據和指令在程序中的地址(程序地址或虛擬地址)會被轉換成系統內存使用的物理地址。
如果cache純粹地在物理地址方式下工作,將很容易被管理(我們將在後面討論爲什麼)。但合法的虛擬地址可以讓cache更早地開始查詢匹配工作,這樣可以使系統跑的稍微塊一點。
但虛擬地址有什麼問題呢?它們不是唯一的;當許多不同的程序在CPU不同的地址空間中運行,它們可能會共享同樣的虛擬地址而使用不同的數據。當我們切換不同的地址空間時,每次都需要重新初始化cache;這種方式在很多年前被使用,可以作爲針對非常小的cache的一種合理解決方法。但針對大的cahce這種方式不僅可笑而且效率低下,我們需要一塊區域來辨別cache tag中的地址空間,以至我們不被它們混淆。
這兒還有其它關於虛擬地址更細緻的問題:相同的物理地址可以在不同的任務中被不同的虛擬地址描述。這就會導致相同物理地址的內容會被映射到不同的cache條目中(因爲它們對應不同的虛擬地址,所以會被不同的索引所選中)。這樣的情況必須被操作系統的內存管理所避免掉。詳細的情況將在4.14.2節介紹。
從R4000起,MIPS的主cache都使用虛擬地址索引,從而提供快速的cache索引。但對於作爲標記符來標記每一個cache-line,物理地址比虛擬地址更好。物理地址是唯一的而且效率更高,因爲這樣的設計顯示出CPU在做cache索引的同時可以把虛擬地址轉換成物理地址。

line大小的選擇(Choice of line size):
line的大小是對應每一個tag可以存貯多少字的數據。早期的MIPS的cache對應一個tag只能存貯一個字的數據。但對應一個tag能存貯多個字的數據更好,尤其是內存系統支持快速的burst read。現代的MIPS cache趨向於使用四個或者八個字大小的line,並且更大的第二層和第三層cache使用更大的line。
當cache miss發生時,整個一條line的數據都要從內存中獲得。但很可能會取來幾line的數據;一個字的cache line的MIPS CPU經常是一次就取多個字的數據。

分開/統一(Split/unified):
MIPS的主cache總是分成I-cache和D-cache,取指令時察看I-cache,讀寫數據時察看D-cache。(順便說一下,如果你想執行CPU剛剛拷貝到內存的代碼,你必須不僅僅要是D-cache一部分無效使這些代碼數據在D-cache中不再存在,而且還要保證它們被裝入I-cache)
但是不在同一塊芯片上的第二層cache很少也按這種方式來分成兩塊。這樣就沒有什麼真的優勢可言了。除非你能針對兩種cache提供分開的數據總線,但這又會需要太多的管腳。

4.6 Cache管理(Magaging Caches)
Cache系統在系統軟件的幫助下,必須保證任何應用程序數據的一致性,和它們在沒有cache的系統下一樣,尤其是DMA I/O控制器(直接從內存中取得數據)取得程序認爲已經寫過的數據。
對於CISC CPU,通常都不需要系統軟件對cache的幫助;因爲它會花費額外的內存空間、silicon area、時鐘週期來使得cache變得真正的透明。
在系統啓動的時候MIPS CPU需要初始化它的cache;這是一個十分複雜的過程,下面有關於它的幾點建議。但當系統啓動後運行到三種情況CPU必須加以干涉。


.在DMA設備從內存取數據之前:
如果一個設備從內存中取得數據,它必須取得正確的數據。如果D-cache是write-back,並且程序已經寫了一些數據,那麼很可能其中一些正確的數據還保留在D-cache中而沒有寫回到主存中去。CPU當然不可能看到這個問題;如果CPU需要這些數據,它會從cache中得到正確的數據。
所以在DMA設備開始從內存中讀數據前,任何一個將被讀數據如果還保留在D-cache中,必須被寫回到內存中。

. DMA設備寫數據到內存:
如果一個設備要將數據存貯到內存中,要使cache中任何對應將要寫入內存位置的line都無效化,這是非常重要的。否則,CPU讀這些位置的數據,將得到錯誤的數據。cache應該在數據通過DMA寫入內存之前將對應的cache line無效化。

. 拷貝指令:
當CPU自己爲了後面的執行而寫一部分指令到內存中,你首先必須保證這些指令會被回寫到內存中,其次保證I-cache中對應這些指令的line會被無效化。在MIPS CPU中,D-cache和I-cache是沒有任何聯繫的。(當CPU自己寫指令到內存中時,這時候指令是被當作數據寫的,很可能只被寫到cache中,所以我們必須保證這些指令都會被回寫到內存中;爲什麼要使I-cache無效化,這和數據通過DMA直接寫入內存中要無效cache一樣的原因。)


如果你的軟件需要解決這些問題,就需要針對cache line的兩個獨特的操作。
第一個操作被稱之爲回寫操作。CPU必須能夠針對地址在cache中查找對應的cache line。如果找到,並且對應line是dirty,就需要把這條line的數據寫回到內存中。
CPU增加了其他不同層次的cache(速度和大小),來減少miss的處理。所以設計者可以使內層的cache機構簡單,從而使它能在很高的時鐘頻率上作查詢。這樣很顯然越往內層的cache就會越小。從1998年開始,許多高速的cpu都在同一塊芯片上採用第二級cache,主cache的大小變小,雙重16K的主cache受到青睞。

不在同一塊芯片上的cache通常都是直接映射的,因爲組相連的cache系統需要更多的總線從而需要更多的管腳來連接。這還是一個值得研究的領域;MIPS R10000採用只有一個數據總線的二路組相連cache,如果命中的不是希望的那一組,通過一段延時後在返回數據來實現(兩個組共用一個數據總線)。
在cache的發展過程中,產生了兩類主要的軟件接口來針對cache。從軟件的觀點來看,一類是建立在以R3000爲代表的32位MIPS CPU的基礎上;另一類是建立在以R4000爲代表的64位MIPS CPU上的。R3000這一類型的MIPS CPU的cache是write-through,直接映射的,物理地址爲索引。cache訪問的最小單位是一個字,所以寫一個字節(或者是寫小於一個字)的操作必須被特殊的處理。在讀寫這一類數據是cache管理採用特殊的模式。

爲什麼不通過硬件來管理cache?
通過硬件來管理cache通常被稱爲“愛管閒事”。當另一個cpu或者是DMA設備訪問內存時,被訪問地址對應的內容對於cache來說是可以看到的。

4.7 第二層和第三層cache
在大型的系統中,通常需要一個嵌套的多層cache。一個小而快的主cache最接近cpu。訪問主cache出現miss時,不是直接從內存中查找而是從第二層cache中查找。第二層cache在速度和大小上是介於主cache和內存之間。cache層次的數目可以通過內存速度和cpu最快訪問速度比較來決定;由於cpu速度發展比內存的發展快得多,在過去的12年裏桌上型電腦系統從沒有cache發展到有兩層cache。九十年代後期的最快cpu速度大約可以達到500MHz,擁有三層cache。

 


4.8 MIPS CPU cache的構造
通過觀察cache採用模式和層次的發展(看錶4.1),我們可以將MIPS CPU分成兩類,古老的和現代的。
當時鐘的速度變得越快,我們就能看到越多得cache構造,因爲設計者爲了應付CPU跑得速度比內存系統越來越快。爲了保證運行的順暢,cache必須提高運行速度,保證提供數據的速度比外圍得存貯器要快,同時也要保證儘可能多命中。相比較R4000類型的CPU,主cache是write back類型,是write allocate ,virtually indexed,physically tagged, 二路或四路組相連的cache。
許多R4x00和其後續cpu在同一塊上擁有第二層cache的控制器,1998年出現了這樣的第一塊cpu。
由於兩種產生的不同,我們將分兩節來詳細介紹。

注意!一些系統的第二層cache不是由mips cpu內部的硬件來控制的,而是建立在內存的總線上。對於這類cache的軟件接口將具有系統特殊性,和象這章介紹的由cpu內部控制的cache的軟件接口相比,可能有很大的不同。

4.9 Programming R3000-Style Caches
MIPS R2000打破了芯片內cache控制器的基礎,將cache額外的分成I-cache和D-cache。這是一個後見之明,不會讓人感到驚訝,就是這樣一個先驅者的冒險導致了後面很多事端。cache有一個特殊的軟件訪問缺點。
爲了節省芯片管腳,cache將不能擁有不同的閘門來執行字節、半個字和其他小於一個字單位的寫操作。所以在R2000系列中對cache執行一個小於字單位的寫操作時,會回寫到主存中,並將cache中這個字所在的Line無效化。這樣針對cache管理,提供了一個使cache無效的方法:只用寫一個字節就行了。
你可以看到支持這些簡化的觀點。R2000設計者提出理由小於字的操作通常用於字符操作,字符操作總是由庫函數提供,而這些庫函數用整個字的操作來重寫。這些假設總是被認爲對對錯錯,或者半對半錯。
直到認識到不是所有系統都能用相同的函數庫,而且每個字節寫操作都使所在cache無效也不是一個好主意,這些爭論纔沒有繼續下去。因爲這是不能被容忍的,所以出現了一個很大的改動,R3000系列的cpu通過一個RMW(read-modify-write)序列來執行小於字單位的寫操作。這個RMW出現在所以的32位的mips cpu中,並增加了一個 時鐘週期來作爲這樣一個寫操作的延時。
這樣cache無效的機制被帶入困境;R2000因爲它的奇怪習慣而有一個優點,可以通過字節的寫操作來使cache無效化。而R3000 cache 需要用一個叫isolation的模式來挽救,原來這種模式只是用於cache診斷的。RMW隊列因爲這種模式而受到壓制,在那種狀態下小於一個字單位的寫操作還是會讓該字所處的line無效化。這是不幸的但不是悲慘(災難)的,對於一些運行着的系統做一些事有着更有益的地方。顯著的就是當cache在isolation模式時的時候,cache將沒有讀寫操作,任何讀寫操作將直接和內存打交道。

4.9.1 Using Cache Isolation and Swapping
所有的R3000系列cpu的cache都是write-through模式的,這就是說cache中不會擁有比內存中更新的數據。也就是說cache中的數據從來都不需要回寫到內存,所以我們只需要能使D-cache和I-cache無效就行了。
只需要不同的cache操作按照內存順序來做cahce的管理,並且cache的管理沒有必要通過特殊的內存地址空間。所以這兒有一個狀態寄存器有一個SR位能夠使D-cache關閉isolation模式;在這種模式下讀寫操作隻影響着cache,讀還是會命中但不管tag是不是相等。當D-cache處於isolation模式時,小於一個字單位的寫操作會使對應cache Line被無效化。

CAUTION!!!
當D-cache處於isolation模式,任何讀寫操做不會受其對應地址或TLB條目的影響而按照非cache的情況操作。這樣的結果就是cache管理程序必須保證有些數據是不可以被訪問的;如果你能通過你的編譯器做到很好的控制,並且能過保證所有你用的變量都保存在寄存器中,你才能在很高級別的語言中寫它們。還必須保證運行這些程序時屏蔽中斷。

I-cache在通常運行模式下也是完全不可訪問的。所以CPU提供了另一種模式,cache交換(swapped),通過設置狀態寄存器的SwC位;這時D-cache可以擔當I-cache,I-cache可以擔當D-cache。當cache是交換模式時,isolated的I-cache條目可以被讀、寫和無效化。
D-cache可以完美的充當I-cache使用(可能I-cache也可以通過初始化使之象D-cache一樣工作),但I-cache不能完全的充當D-cache。這也是靠不住的,當cache是交換模式時有用,isolation卻沒有用。
如果你需要使用交換的I-cache來存儲字單位的數據(和以前一樣小於字單位的數據寫操作會使該數據對應的line被無效化),你必須保證在返回到正常模式時對應的cache line必須被無效化。

4.9.2 Initializing and Sizing 初始化和判斷大小
當機器啓動時cache的狀態是不確定的,所以這時讀cache結果也是不可預知的。你也應該認識到機器重起後狀態寄存器的SwC位和IsC位也是不確定的,所以在對cache讀寫前(即使在非cache的情況)啓動軟件最好能將這些狀態設爲可知的。
不同的MIPS CPU,cache有不同的大小。爲了保證你軟件的可移植性,最好能在初始化的時候計算出D-cache和I-cache的大小。這樣比直接配置一個給定的值好。
下面將介紹怎樣獲得cache大小的值:
a. Isolated cache,讓I-cache處於交換模式。
b. 在R3000系列CPU中,cache的大小可能是256K,128K,64K,32K,16K,8K,4K ,2K,1K和0.5K(K等於1024,單位是字節)。將這些可能的值n(上面那些值中的一個)寫到物理地址等於它們本身的地方(有大到小)。最簡單產生物理地址是用Kseg0段地址(n+0x80000000)。因爲cache地址是重疊循環的,那麼如果n是cache大小的倍數,那麼它就會被後面小的值所覆蓋。
c. 所以讀物理地址零(也就是0x80000000),就能得到cache大小的值。

初始化cache,你必須保證每一個cache條目都被無效化,而且正確對應一個內存位置,所含的之值也是正確的:
a. 檢查狀態寄存器SR的PZ位是不是位零(爲1的話,關閉奇偶位,對於同一個芯片上的 cache這不是一個好主意)。
b. isolated D-cache,並使它和I-cache交換。
c. 對於cache的每一個字,先寫一個字的值(使cache的每條line的tag、數據、和奇偶位都正確),然後再寫一個字節(使每條line都無效)。
不過要注意當對於每條line有四個字的I-cache,這樣做效率就很低;因爲只要寫一個字節就足夠使每條line無效了。當然除非你要經常調用這個使cache無效程序,否則這個問題是不會表現的很明顯。不過如果你想根據實際情況來優化cache無效化程序,就需要在啓動的時候確定cache的結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章