【轉載】DSP 緩存機制及影響測試

本文主要以DSP講解cache原理,但原理與CPU是相通的,故轉載,原文地址:https://blog.csdn.net/qq_39376747/article/details/112794096數組

DSP 緩存機制

注:本文說明的DSP基於TI c6000系列的C66x DSP緩存

1.Cache基礎

通常來講咱們的代碼每每是存放在咱們的磁盤設備中(EMMC、SSD、Flash等),當咱們運行程序的時候,咱們須要將代碼加載到咱們的內存(DDR)中去運行,以後CPU再從內存中加載代碼執行,可是相比較而言計算機CPU的運行速率與咱們的DDR內存的運行速率,兩者有着近百倍的速度差別,因此當咱們實際運行一段代碼的時候,CPU試圖從內存中讀取或寫入一段數據的時候,每每會由於兩者的速度差別而白白去等待形成性能上的浪費,因此爲了解決這個問題,咱們設計了緩存機制,即在CPU和內存之間增長一個速度極快可是容量極小的設備,咱們稱這段存儲爲Cache,CPU會首先從cache中查找對應地址的數據是否緩存在cache 中。若是其數據緩存在cache中,直接從cache中拿到數據並返回給CPU。
在這裏插入圖片描述點擊並拖拽以移動架構

1.1 Cache命中和缺失

當CPU想要訪問一段數據的時候,會先訪問緩存,當咱們須要的數據在cache中有被緩存到,咱們就稱爲一次「命中(hit)」,反之當數據不存在的時候,咱們稱爲一次」缺失(miss)「。當咱們的計算機系統存在多級緩存的時候,計算機在進行數據訪問的時候會逐級進行查找,即:CPU首先從 L1 cache 進行查找,當數據幸運躺在L1 cache時,咱們就將數據返回給CPU(一次緩存命中),可是當L1 cache不存在這段數據的話,CPU會將這一次查找延伸到下一級緩存L2 cache,那麼L1 cache的訪問就是一次緩存缺失;CPU在L2 cache進行查找的時候,若是命中了就會將數據返回給CPU(數據給不給L1 cache是基於L1的分配策略的,後面講),若是缺失就繼續延伸到下一級緩存(若是不存在後續緩存就到內存中查找)app

在這裏插入圖片描述點擊並拖拽以移動

1.2 Cache line

咱們在看一個芯片的屬性的時候,每每會看到一條cache size,這個表明了咱們的緩存的大小也表示緩存的數據容量,而cache line表示的就是緩存行,它的大小稱爲cache line size。cache line是操做cache的最小單位,這句話如何理解呢,假設咱們的cache line是32字節,咱們須要讀取的數據的大小爲4字節,當咱們緩存這段數據的時候,cache不會只單單緩存4字節,而是一次緩存32字節(一行的數據量),這就比如緩存是一塊蛋糕8斤,咱們平均切了8刀,這每一塊一斤就至關於一個緩存行,你想吃一小塊二兩,不能夠,吃二兩也給你一斤。因此cache每一次操做數據的最小單位名就是一個cache line size。
在這裏插入圖片描述點擊並拖拽以移動ide

1.3 Cache分類

對於緩存的分類,從存儲層次上來講,cache能夠分爲L1 cache、L2 cache、L3 cache,其中級數越靠後則速度越慢當容量越大;按照數據映射的方式不一樣,咱們能夠將緩存分爲直接映射緩存、組相連緩存、全相連緩存。下面咱們重點介紹一下這幾種分類:性能

1.3.1 直接映射緩存(Direct-Mapped Caches)

在這裏插入圖片描述點擊並拖拽以移動
在瞭解什麼是直接映射緩存以前咱們須要先理解上面這一幅圖的含義,咱們上圖的右邊的L2 SRAM 能夠理解爲咱們的一塊存儲區域,當CPU讀取一個數據時會先從左邊的L1 cache中去找,當沒有找到咱們想要的內容時即爲一個Miss,就會去右邊的SRAM中去找而後將SRAM中的這一塊區域緩存到cache中。咱們的地址是32位的,分紅了三個部分:Offset(5位)、Line/set(9位)、Tag(18位)。其中Offset表示咱們的偏移,大小爲5表示咱們的當前緩存一行能夠存放2的5次方(32)字節大小的數據量,Offset與內存地址的對應關係以下圖所示。
在這裏插入圖片描述點擊並拖拽以移動
以此類推,當咱們的地址的第6位爲1時,表示進入了下一層Line。咱們就在 Line/set 部分開始進行索引。當咱們的 Line/set 部分與 Offset 部分所有索引完畢後,咱們會對 Tag 部分和 標誌位Valld 進行比較,當咱們cache中的 Tag 部分與Memory address的 Tag 部分相等而且 標誌位Valld 爲1(即:緩存有效),這表示cache中存在當前Memory address的內容,視爲一次命中(hit),不然視爲一次未命中(miss)。
在這裏插入圖片描述點擊並拖拽以移動
假設咱們的cahce的大小是16K的,如今有三塊內存區域,咱們能夠看到圖中的這三塊內存空間都所有覆蓋了整個cache,當咱們試圖訪問0x000九、0x400九、0x8009這三個地址的時候,咱們會發現這三個地址空間的 Line/set 部分與 Offset 部分都相等,只有 Tag部分不一樣。所以,這3個地址對應的cache line是同一個。因此,當咱們訪問0x0009地址時,cache會缺失,而後數據會從主存中加載到cache中第0行cache line。當咱們訪問0x4009地址時,依然索引到cache中第0行cache line,因爲此時cache line中存儲的是地址0x0009地址對應的數據,因此此時依然會cache缺失。而後從主存中加載0x4009地址數據到第0行cache line中。同理,繼續訪問0x8009地址,依然會cache缺失。這就至關於每次訪問數據都要從主存中讀取,因此cache的存在並無對性能有什麼提高。訪問0x4009地址時,就會把0x0009地址緩存的數據替換。這種現象叫作cache顛簸(cache thrashing)。而對於這種一對一緩存的方式的cache咱們稱爲直接映射緩存。測試

1.3.2 組相連緩存( Set-Associative Caches)

理解組相連緩存,咱們需先要了解什麼是路(Way),咱們將cache平均分紅多份,每一份就是一路。所以,兩路組相連緩存就是將cache平均分紅2份,四路組相連緩存就是將cache平均分紅4份。在DSP C66X中,L1D cache 是兩路組相連緩存,L2 cache是四路組相連緩存。
在這裏插入圖片描述點擊並拖拽以移動
針對上一節咱們分析的那個內存訪問示例,當咱們使用兩路組相連緩存的時候,如今0x0009地址的數據能夠被加載到way 0x4009能夠被加載到way。這樣就在必定程度上避免了直接映射緩存的尷尬境地。在兩路組相連緩存的狀況下,0x0009和0x4009地址的數據都緩存在cache中。若是咱們是4路組相連緩存,後面繼續訪問0x8009,也可能被緩存。ui

1.3.3 全相連緩存(Full associative cache)

在這裏插入圖片描述點擊並拖拽以移動
全相連緩存的cache line都在同一行,所以地址中不須要set/line部分,咱們根據地址中的tag部分和全部的cache line對應的tag進行比較(硬件上可能並行比較也可能串行比較)。哪一個tag比較相等,就意味着命中某個cache line。所以,在全相連緩存中,任意地址的數據能夠緩存在任意的cache line中。因此,這能夠最大程度的下降cache顛簸的頻率。可是硬件成本較高。C66X中不存在這種緩存。.net

1.4 Cache更新策略(Cache update policy)

當咱們的Cache在命中的時候,會涉及到cache的更新策略(固然命中也分讀命中和寫命中,讀操做不涉及緩存更新,也就不存在什麼更新策略),Cache的更新策略分爲寫直通和寫回。設計

1.4.1 寫直通(write through)

當CPU要寫一個數據的時候並在Cache命中時,咱們會更新cache中的數據並更新內存中的數據,這樣cache和內存中的數據會始終保持一致,不會存在髒位。

1.4.2 寫回(write back)

當CPU要寫一個數據的時候並在Cache命中時,咱們只會更新cache中的數據,除非咱們cache line被替換或者說咱們進行緩存同步操做,否則內存的數據不會更新,同時當咱們更新cache中的數據時,咱們還會將當前的cache line標記爲「髒」,即 dirty bit 置一,表示當前緩存行內容更新過。在cache執行寫回策略時,可能存在cache和內存不一樣的狀況。因此咱們須要注意緩存一致性的問題。

1.5 Cache分配策略(Cache allocation policy)

當CPU在訪問cache時發生了缺失時,cache會依據當前緩存的分配策略來進行數據的緩存操做,通常分爲讀分配和寫分配。

1.5.1 讀分配(read allocation)

當咱們的緩存支持讀分配時,在發生cache缺失的時候,緩存會分配一個緩存行(cache line)來緩存源於下一次存儲設備的數據。

1.5.2 寫分配(write allocation)

當咱們的緩存支持寫分配時,咱們首先從主存中加載數據到cache line中(至關於先作個讀分配動做),而後會更新cache line中的數據。當是當咱們不支持寫分配時,寫指令只會更新內存的數據。

2 一級程序內存和緩存

2.1. 一級程序(L1P)內存和緩存的用途

1級程序(L1P)存儲器和緩存的目的是使代碼執行的性能最大化。 L1P緩存的可配置性提供了許多系統所需的靈活性。L1P高速緩存對於促進以快速時鐘速率獲取程序代碼是必要的,以便維持較大的系統內存。 高速緩存負責隱藏與讀取和寫入較慢的系統內存相關的延遲。

2.1.1 功能

L1P內存和緩存提供了使用C66x CorePac的設備所需的內存靈活性。能夠將部分或所有L1P轉換爲緩存。 L1P支持4K,8K,16K和32K的緩存大小。L1P高速緩存經過從L1P內存映射的頂部開始向下進行工做,將內存從RAM轉換爲高速緩存。 解釋一下,L1P存儲器的最高地址首先成爲高速緩存。

• 當配置爲告訴緩存時,L2內存是具備32字節高速緩存線的直接映射高速緩存
• 可徹底配置爲高速緩存或SRAM
• L2 存儲器控制器具備糾錯碼(ECC)和 ED 機制
• 不支持錯誤校訂或檢測
• L2內存的頁大小爲2K

2.1.2 L1P緩存架構

L1P高速緩存是直接映射的高速緩存,這意味着系統中的每一個物理內存位置在其可能駐留的高速緩存中都有一個可能的位置。 當DSP嘗試獲取一段代碼時,L1P必須檢查所請求的地址是否位於L1P高速緩存中。 爲此,將DSP提供的32位地址劃分爲三個字段(tag, set, and offset),以下圖所示。
在這裏插入圖片描述點擊並拖拽以移動
5位的偏移量說明L1P行大小爲32個字節。 高速緩存控制邏輯忽略地址的位0到4。 set字段指示數據將駐留的L1P緩存行地址(若是已緩存)。 設置字段的寬度取決於配置爲緩存的L1P的數量。 L1P使用set字段來查找並檢查標籤中是否有來自該地址的任何已緩存數據以及有效位,該有效位指示標籤中的地址是否實際上表示緩存中保存的有效地址。標籤字段是地址的上部,用於標識數據元素的真實物理位置。 在程序讀取時,若是標籤匹配而且設置了相應的有效位,則爲「命中」,而且直接從L1P緩存位置讀取數據並將其返回給DSP。 不然,這是一個「缺失」,請求將被髮送到L2·,從系統中的位置獲取數據。 遺漏可能會或可能不會直接致使DSP停頓。

2.2 一級數據(L1 D)內存和緩存的用途

L1D存儲器和高速緩存的目的是使數據處理的性能最大化。 L1D存儲器和高速緩存的可配置性提供了在系統中使用L1D高速緩存或L1D存儲器的靈活性。C66x L1D存儲器和高速緩存體系結構容許將L1D的部分或所有轉換爲讀分配,回寫,雙向集關聯高速緩存。 高速緩存對於促進以全DSP時鐘速率讀寫數據是必需的,同時仍具備較大的系統內存。 隱藏與讀取和寫入較慢的系統內存相關的大部分延遲是緩存的責任。

2.2.1 特徵

L1D內存和緩存提供如下功能:
• 當配置爲告訴緩存時,L2內存是具備64字節高速緩存線的2路組關聯高速緩存
• 可徹底配置爲高速緩存或SRAM
• L2 存儲器控制器具備糾錯碼(ECC)和 ED 機制
• 不支持錯誤校訂或檢測
• L2內存的頁大小爲2K

2.2.2 L1 D緩存架構

L1D高速緩存是雙向設置關聯高速緩存,這意味着系統中的每一個物理內存位置在高速緩存中能夠駐留的位置都有兩個可能的位置。 當DSP嘗試訪問一條數據時,L1D高速緩存必須檢查請求的地址是否以L1D高速緩存的任何一種方式駐留。 爲此,DSP提供的32位地址被分爲六個字段,以下圖所示。
在這裏插入圖片描述點擊並拖拽以移動

2.3 總結

c66x的一級緩存分爲一個可分配的32K的L1D cache和一個可分配的32K的L1P cache,其中L1P是一個直接映射緩存,支持讀分配無寫分配,Line size的大小爲32字節;L1D是一個兩路組相干緩存,支持讀分配和寫回操做,Line size的大小爲64字節。

3 二級程序內存和緩存

3.1 二級程序(L2)內存和緩存的用途

L2存儲器控制器在較快的1級存儲器(L1D,L1P)和較慢的外部存儲器之間提供了片上存儲器解決方案。 其優勢在於,它支持比L1存儲器更大的存儲器大小,同時提供比外部存儲器更快的訪問速度。與L1存儲器相似,您能夠將L2配置爲同時提供緩存和非緩存(便可尋址)存儲器。

3.2 特徵

L2內存和緩存提供如下功能:
• 當配置爲告訴緩存時,L2內存是具備128字節高速緩存線的4路組關聯高速緩存
• 只有256KB的 L2 內存能夠配置爲cache或SRAM
• L2 存儲器的32KB老是映射爲SRAM
• L2 存儲器控制器具備糾錯碼(ECC)和 ED 機制
• L2內存控制器支持硬件預取,還提供帶寬管理、內存保護和掉電功能
• L2內存的頁大小爲16K

4 cache相關寄存器

4.1 L1P相關寄存器

AM 5728關於DSP C66x核心相關的控制寄存器分爲3組,每一組寄存器控制一種類型的cache,其中L1P cache相關的寄存器以下:
在這裏插入圖片描述點擊並拖拽以移動

L1P配置寄存器(L1PCFG)

L1P配置寄存器(L1PCFG)控制L1P緩存的大小,以下圖所示:
在這裏插入圖片描述點擊並拖拽以移動
該寄存器能夠設置L1Pcache的模式,當該寄存器的02位設置爲0時表示該緩存不使能,設置爲14表示不一樣大小的cache空間,設置爲5~7表示最大的cache空間。

L1P緩存控制寄存器 (L1PCC)

L1PCC緩存控制寄存器(L1PCC)控制L1P是凍結仍是未凍結。
在這裏插入圖片描述點擊並拖拽以移動
該寄存器能夠設置L1P cache的凍結模式,其中第0位(OPER)設置爲1表示使能凍結模式,設置爲0不使能;第16位是隻讀位,存儲上一次OPER位的值。

L1P無效的基址寄存器(L1PIBAR)

L1P無效基地址寄存器(L1PIBAR)定義了相關操做將做用於的塊無效的基地址。
在這裏插入圖片描述點擊並拖拽以移動

L1P無效字數寄存器(L1PIWC)

L1P無效字計數寄存器(L1PIWC)定義了相干運算將要做用於的塊無效的大小。 大小以32位字定義。
在這裏插入圖片描述點擊並拖拽以移動
經過該寄存器咱們能夠設置塊無效的字數。

L1P無效寄存器(L1PINV)

L1P失效寄存器(L1PINV)控制L1P緩存的全局失效,以下圖所示。
在這裏插入圖片描述點擊並拖拽以移動
該寄存器能夠設置L1P cache line的失效,其中第0位設置爲1表示全部緩存行失效,設置爲0表示緩存行爲正常模式。

4.2 L1D相關寄存器

L1D cache支持寫回操做,因此L1D包含的寄存器會多幾組,具體以下:
在這裏插入圖片描述點擊並拖拽以移動
在這其中L1DCFG、L1DCC、L1DIBAR、L1DIWC、L1DINV的做用於L1P cache寄存器類似,因此在此不作說明。在此我說明一下剩下的6個寄存器.

L1D寫回基地址寄存器(L1DWBAR)

在這裏插入圖片描述點擊並拖拽以移動
定義L1D塊寫回操做的基地址。

L1D寫回寄存器(L1DWB)

在這裏插入圖片描述點擊並拖拽以移動
該寄存器設置將cache裏的內容寫回到下一級內存中,當寄存器第0位設置爲1時,則會將全部的髒行寫回。

L1D寫回無效寄存器(L1DWBINV)

在這裏插入圖片描述點擊並拖拽以移動
該寄存器設置將cache裏的內容寫回到下一級內存中,並將該緩存行設置爲失效,當寄存器第0位設置爲1時,則會將全部的髒行寫回,並使緩存行失效。

L1D寫回基地址寄存器(L1DWBAR)

L1D回寫基地址寄存器(L1DWBAR)定義了將回寫的塊的基地址。
在這裏插入圖片描述點擊並拖拽以移動
定義L1D塊寫回操做的基地址。

L1D寫回無效字計數寄存器(L1DWIWC)

L1D寫回無效字計數寄存器(L1DWIWC)定義了將被寫回並沒有效的塊的大小。 大小以32位字定義,以下圖所示。 L1DWIBAR地址和L1DW1WC字數的組合所觸及的全部高速緩存行都將無效,而只回寫指定的數據。
在這裏插入圖片描述點擊並拖拽以移動

4.3 L2相關寄存器

L2寄存器組與L1D類似,具體以下:
在這裏插入圖片描述點擊並拖拽以移動
這裏大部分寄存器與L1D的寄存器類似,在這裏不作介紹,咱們着重說明一個寄存器是L2CFG,該寄存器與L1DCFG和L1PCFG存在較大差別。具體以下。
在這裏插入圖片描述點擊並拖拽以移動
該寄存器除了配置L2緩存的一些屬性,還能夠操做L1D和L1P

4.4 MARn寄存器組

4.1~4.3介紹的寄存器均爲設置cache自己的寄存器,可是若要使咱們的內存可以真正緩存到cache中,除了須要設置咱們的cache之外,還需配置咱們須要緩存的內存段的可緩存性,只有當咱們將內存段的可緩存性設置爲緩存使能,咱們這塊內存中存儲的內容纔會被緩存至cache,MAR寄存器組就是完成內存段的屬性設置。
在這裏插入圖片描述點擊並拖拽以移動
MARn寄存器組是一組寄存器,這裏n的取值爲0~255,這256個寄存器每個能夠設置一塊16M的內存空間的屬性。以下:
在這裏插入圖片描述點擊並拖拽以移動
例如咱們須要緩存的數據段是0xF800_0000 ~ F900_0000,則咱們須要找到這段內存所對應的寄存器即 MAR248 ,以後咱們只需將該寄存器的第0位(PC位)設置爲1(可緩存使能)便可。

5.緩存的使用

在DSP復位的時候,默認會以最大緩存量使能L1 cache,L2cache則所有設置爲SRAM,但這樣咱們內存中的內容其實是不會緩存到cache中的,咱們設置cache須要做出如下的幾個步驟,因爲c66x DSP支持CSL庫,因此咱們只需調用相應的API便可,無需直接設置寄存器:

1.初始化L1P,用戶可按需求設置爲4K 、8K 、16K 、32K

(API:static inline void CACHE_setL1PSize (CACHE_L1Size newSize).

2.初始化L1D,用戶可按需求設置爲4K 、8K 、16K 、32K

(API:static inline void CACHE_setL1DSize (CACHE_L1Size newSize))

3.初始化L2,用戶可按需求設置爲32K 、64K 、128K 、256K、512K、1024K、

(API:static inline void CACHE_setL2Size (CACHE_L1Size newSize))

4.設置內存段的可緩存屬性

(API:static inline void CACHE_enableCaching (Uint8 mar))

5.使緩存失效,並等待緩存失效操做完成

6.測試

咱們在內存(DDR)中設置一個4KB大小的數組,咱們對該數組進行讀寫來模擬4K的數據量交互,經過對比讀寫相同4K數據量的所耗時間來比較 cache對於性能的影響:

經過使用CCS 咱們能夠知道代碼運行的所消耗的時鐘週期,因此咱們只需對比測試代碼中兩個for循環的耗時便可得出4K數據讀寫的總耗時。
注意:本測試進行與DSP c66x 裸機環境

6.1 測試一: 開啓cache;

在這裏插入圖片描述點擊並拖拽以移動
耗時:37402個時鐘週期

6.2 測試二: 不開啓 cache

在這裏插入圖片描述點擊並拖拽以移動
耗時:1305155個時鐘週期。

6.3 4K數據量的完整測試結果

在這裏插入圖片描述點擊並拖拽以移動

總結:咱們能夠看出cache對於內存的讀寫會存在較大的影響,讀寫相同的數據量,使用緩存的耗時遠遠小於不使用緩存的,cache對性能的提高有較大做用。

參考資料: 《sprugy8 – TMS320C66x DSP Cache User Guide》 《高速緩存與一致性專欄 – 知乎》

相關文章
相關標籤/搜索