DMA导致的CACHE一致性问题解决方案
學習筆記
轉載:https://blog.csdn.net/waterhawk/article/details/50723677
轉載:https://blog.csdn.net/jasonchen_gbd/article/details/79462064
先簡單說一下DMA的CACHE一致性是個啥問題?
CPU在訪問內存時,首先判斷所要訪問的內容是否在Cache中,如果在,就稱為“命中(hit)”,此時CPU直接從Cache中調用該內容;否則,就 稱為“ 不命中”,CPU只好去內存中調用所需的子程序或指令了。CPU不但可以直接從Cache中讀出內容,也可以
直接往其中寫入內容。由于Cache的存取速 率相當快,使得CPU的利用率大大提高,進而使整個系統的性能得以提升。
Cache的一致性就是直Cache中的數據,與對應的內存中的數據是一致的。
DMA是直接操作總線地址的,這里先當作物理地址來看待吧(系統總線地址和物理地址只是觀察內存的角度不同)。如果cache緩存的內存區域不包括DMA分配到的區域,那么就沒有一致性的問題。但是如果cache緩存包括了DMA目的地址的話,會出現什么什么問題呢?
問題出在,經過DMA操作,cache緩存對應的內存數據已經被修改了,而CPU本身不知道(DMA傳輸是不通過CPU的),它仍然認為cache中的數 據就是內存中的數據,以后訪問Cache映射的內存時,它仍然使用舊的Cache數據。這樣就發生Cache與內存的數據“不一致性”錯誤。
來個外語的:
The cache.
This entity is essentially "memory state" as the flush architecture views it. In general it has the following properties:
It will always hold copies of data which will be viewed as uptodate by the local processor.
Its proper functioning may be related to the TLB and process/kernel page mappings in some way, that is to say they may depend upon each other.
It may, in a virtually cached configuration, cause aliasing problems if one physical page is mapped at the same time to two virtual pages, and due to to the bits of an address used to index the cache line, the same piece of data can end up residing in the cache twice, allowing inconsistancies to result.
Devices and DMA may or may not be able to see the most up to date copy of a piece of data which resides in the cache of the local processor.
Currently, it is assumed that coherence in a multiprocessor environment is maintained by the cache/memory subsystem. That is to say, when one processor requests a datum on the memory bus and another processor has a more uptodate copy, by whatever means the requestor will get the uptodate copy owned by the other processor.
(NOTE: SMP architectures without hardware cache coherence mechanisms are indeed possible, the current flush architecture does not handle this currently. If at at some point a Linux port to some system where this is an issue occurrs, I will add the necessary hooks. But it will not be pretty.)
以前接觸比較多的幾種內存機制:
帶CACHE的內存有兩種,寫回(writeback)、寫穿(writethrough);或者非CACHE空間。
搞DMA的時候發現非CACHE其實還可以細分兩種,一致(coherent),寫緩存(writecombine)。
其實后面這兩種,網上也找不到標準的翻譯方法,以前書上也沒具體介紹過,純屬自己瞎翻譯。
又一個因為復制粘貼導致的網絡上流行結果:
一致性DMA映射申請的緩存區能夠使用cache,并且保持cache一致性。一致性映射具有很長的生命周期,在這段時間內占用的映射寄存器,即使不使用也不會釋放。生命周期為該驅動的生命周期
千萬別被這句話誤導了,這句是錯誤的。因為,同樣的網頁里以下這段是正確的。
dma_alloc_coherent 在 arm 平臺上會禁止頁表項中的 C (Cacheable) 域以及 B (Bufferable)域。
而 dma_alloc_writecombine 只禁止 C (Cacheable) 域.
?C 代表是否使用高速緩沖存儲器, 而 B 代表是否使用寫緩沖區。
這樣,dma_alloc_writecombine 分配出來的內存不使用緩存,但是會使用寫緩沖區。而 dma_alloc_coherent ?則二者都不使用。
C B 位的具體含義
0 0 無cache,無寫緩沖;任何對memory的讀寫都反映到總線上。對 memory 的操作過程中CPU需要等待。
0 1 無cache,有寫緩沖;讀操作直接反映到總線上;寫操作,CPU將數據寫入到寫緩沖后繼續運行,由寫緩沖進行寫回操作。
1 0 有cache,寫通模式;讀操作首先考慮cache hit;寫操作時直接將數據寫入寫緩沖,如果同時出現cache hit,那么也更新cache。
1 1 有cache,寫回模式;讀操作首先考慮cache hit;寫操作也首先考慮cache hit。
效率最高的寫回,其次寫通,再次寫緩沖,最次非CACHE一致性操作。
其實,寫緩沖也是一種非常簡單得CACHE,為何這么說呢。
我們知道,DDR是以突發讀寫的,一次讀寫總線上實際會傳輸一個burst的長度,這個長度一般等于一個cache line的長度。
cache line是32bytes。即使讀1個字節數據,也會傳輸32字節,放棄31字節。
寫緩沖是以CACHE LINE進行的,所以寫效率會高很多。
簡單寫了一個測試程序,驗證在ARM平臺上的DMA一致性問題。
dst 地址0xab800000, dst 原始數據0x00,長度8
src 地址0xac200000, src 原始數據0x62,長度8
為保證驗證可靠,源地址是一致性內存,目的地址是寫回內存。
實驗步驟:
1. 讀兩個內存數據,用于后續比較,因為源地址是非CACHE的,所以修改一定會被寫到DDR上。
2. 對目的地址的讀8遍。
3. DMA拷貝源到目的地址。
4. 讀目的地址。
實驗結果說明,目的地址讀取到的值依然是0.
解釋:
第二步驟實際作用是為了在cache中,目的地址不被替換出cache。
我們知道一般OS采用的CACHE替換算法都是基于局部性原理,當一個數據在連續時間內經常被操作,則對應的cache line就有更大概率被保留。
而DMA拷貝完成前,只要目的地址的CACHE LINE沒有被替換出去,則DMA完成后,CPU會訪問目的地址時,一定是原始數據。
也就是圖中最終結果,目的地址數據依然是原始數據0x00.
此時CPU訪問的是CACHE,但也有可能訪問的是DDR,甚至可能出現正確結果0x62。
1. 訪問CACHE
這是最簡單的了,因為CACHE LINE沒有被替換,CACHE HIT。所以,CPU不知道DDR數據已經變化,返回原始數據。
2. 訪問DDR
同樣好理解,因為如果之前設置了目的地址的數據,這時該cache line會成為dirty狀態。
在DMA完成之后,如果該cache line被替換到DDR上,那么DDR的數據就又成了原始數據。
目的DDR的變化是 0x00 --> 0x62 (DMA) ?--> 0x00 (cache writeback).
3. 出現正確結果
這個涉及的內容最多。如果之前沒有設置目的地址的值,只是讀目的地址的值,則該cache line是干凈的。
在DMA完成之后,該cache line如果被替換,則cache line里的0x00錯誤數據會被丟棄(因為是干凈的,CACHE認為沒必要寫回)
而CPU在沒有CACHE HIT時,就會從DDR上讀到正確數據0x62.
這同樣說明2個道理,
第一,錯誤的DMA操作,導致了數據一致性的問題,但一定條件下,這個錯誤是不會被感知到的。
第二,即使讀到的100%是正確數據,你也不能從經驗斷定這個程序是對的,但只要有一次錯誤,就可以認為程序是錯誤的了。
我的解決方案:
先上結果
在DMA拷貝前,進行一次CACHE CLEAN,或CACHE FLUSH。
DMA拷貝完成之后,進行一次CACHE FLUSH。
就能很大概率避免一致性的問題。
這個解決方案不是標準的解決方案,使用一致性內存或寫緩沖內存,是無論何時100%正確的。
而這個方案,是一個很大概率的正確方案,在絕大部分合理場景下,可以以最高效率訪問內存。
其實,這個解決方案,大概率按照第一個實驗的條件3執行的。
為什么要執行這2個操作呢。
DMA拷貝前,CACHE CLEAN保證了條件3中所述,目的地址的CACHE LINE是干凈的。最大概率保證DMA傳輸時間內,不會再有寫回動作。
DMA拷貝完成后,CACHE FLUSH保證了,CACHE會重新構建,目的地址的值一定是從DDR上讀取最新數據。
而在拷貝過程中,CPU如果只是讀取目的地址,會直接訪問CACHE,而不訪問DDR。
這個方案使用起來很簡單,但一定要符合以下條件才能取得合理結果(適用于大部分使用DMA的情況):
1. DMA的數據一定是大數據搬移(至少是DCACHE的10倍以上)。因為僅1次CACHE FLUSH就會毀掉你整個DCACHE的數據,至少嵌入式平臺也是128KB以上,這些數據訪問DDR重建也是要時間的。 (這一條保證使用DMA的時間效率)
2.在DMA拷貝期間,不會對目的地址進行寫操作。(這一條可以保證數據絕對正確)
OK,本篇完成了。最后看到linux下老外寫了一個文章,說DMA導致的一致性,linux有一套解決方案,但網上很少人有說,慢慢看。
?
總結
以上是生活随笔為你收集整理的DMA导致的CACHE一致性问题解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实现微信小程序picker 省市区 自定
- 下一篇: html5网页图标