CPU緩存實現方式:VIVT、VIPT和PIPT

處理器在進行存儲器訪問時,處理器訪問的是虛擬地址,經過TLB和MMU的映射,最終變成了物理地址。那麼在查詢cache組的時候,需要使用虛擬地址的索引域或者物理地址的索引域(Index),同樣地,在查詢到cache組之後,可以使用虛擬地址的標記域或者物理地址的標記域(Tag)來匹配cache line. cache可以設計成通過虛擬地址或者物理地址來訪問,這個在處理器設計的時候已經確定下來,可以分成如下三種:

  • VIVT(Virtual Index Virtual Tag):使用虛擬地址索引域和虛擬地址的標記域。
  • VIPT(Virtual Index Physical Tag):使用虛擬地址的索引域和物理地址的標記域。
  • PIPT(Physical Index Physical Tag):使用物理地址的索引域和物理地址的標記域。
    先來看一下VIVT,這種緩存模式直接使用虛擬地址的索引域和標記域來查找cache line,不經過MMU的翻譯,所以查找速度會快一些。然而VIVT的方式可能會導致緩存別名(cache aliasing)的問題,也就是多個相同的虛擬地址可能會被映射到同一個物理地址(synonyms)例如進程間通信,這會導致指向同一個內存地址的虛擬地址的緩存被分開存儲,所以可能產生一致性問題,比如更改了一個虛擬地址的緩存行後,與它指向相同物理地址的虛擬地址的緩存行沒有更改,導致數據不一致。還有可能是相同的虛擬地址指向不同的物理地址(homonyms)(比如說在不同的進程中),僅僅依靠Virtual Index是不能區分這種情況的,不過可以通過清除緩存來解決這一問題(在進程切換的時候不清除緩存),或者可以爲每個虛擬地址空間加個標記(ASID)來區分不同的地址空間。另外還有一個問題是當虛擬地址到物理地址的映射發生變化時,也需要清除一些緩存。所有的這些問題在使用VIPT之後都會迎刃而解。
    再來看一下VIPT,VIPT使用虛擬地址的索引域和物理地址的標記域來查找cache line,它可以避免homonyms問題。至於synonyms問題,以Linux kernel爲例,它是以4kb爲頁面進行管理的,那麼對於一個頁來說,虛擬地址和物理地址的低12bit是相同的,所以不同的虛擬地址映射到同一個物理地址的時候,這些虛擬地址的低12bit也是相同的,在這種情況下,如果索引域在0~12bit之內,那麼這些虛擬地址的cache組是相同的,同樣的它們的Physical Tag也是相同的,那麼這些不同的虛擬地址的cache line在cache裏面是同一個,因此不會產生一致性問題。另外,VIPT其實相比VIVT也沒有太大的性能缺失,按照正常的TLB命中率和一些內部的探測手段可以繞過地址翻譯,那麼VIPT和VIVT相比起來性能也差不多。
    最後看一下PIPT,這種方式下索引域和標記域都採用物理地址,這種方式也可以避免緩存別名問題,不過性能方面要差一些,因爲要先經過地址翻譯的過程。
    緩存對於CPU的性能來說很關鍵,所以一些L1-cache使用的是virtual index,這樣至少能和TLB的查詢過程一起並行地從cache中取出一組數據,然後根據TLB的結果從中選擇Tag相同的那條數據。但是virtual index並不是對於所有級別的緩存都是最佳選擇,緩存別名問題對於越大的緩存解決起來就越代價越大,所以一些二級或更大的緩存使用的是physical index.在過去CPU曾經使用過virtual tag和physical tag,但是現在使用virtual tag的已經不多了,畢竟如果TLB查詢能夠在從cache中返回數據之前結束的話,那就不需要使用virtual tag了。大的緩存都傾向於使用physical tag,只有一些小的、低延遲的緩存才使用virtual tag。在最近的通用CPU中,virtual tag已經被vhints所取代。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章