cache

CPU,內存和cache之間的關係  和 cache的操作

https://blog.csdn.net/vanbreaker/article/details/7470830

cache和內存的關聯方式(associativity)

https://blog.csdn.net/vanbreaker/article/details/7475093

cache的寫策略和多處理器支持

https://blog.csdn.net/vanbreaker/article/details/7477853#comments

cache讀寫機制

https://blog.csdn.net/tc_xjyxhd/article/details/50603007

首先是Write-through和Write-back的區別:(這部分參考:http://witmax.cn/cache-writing-policies.html)

Write-through(直寫模式、寫透模式):數據更新時,同時寫入Cache和下一級存儲。不存在dirty問題。

優點:簡單可靠,不涉及cahce一致性問題;缺點:速度慢(因爲同時寫下一級存儲(比如DDR))。

Write-back(回寫模式):數據更新時,只寫Cache;當數據被替換出來時,纔將該被修改的Cache數據寫到下一級存儲。涉及dirty這個概念。

優點:速度快;下一級存儲沒有副本,若出現意外情況數據將丟失。

順便,dirty:是指cache某個位置數據被更新了,但是還沒更新其對應的下一級存儲位置(即cache不一致);相反

   clean:cache數據與下一級存儲位置數據一致

而allocate是針對cache miss時的處理方式,下面是我的理解:

No-allocate:不論讀、寫操作,cache miss時,直接寫下一級存儲(如DDR)

Read-allocate:讀操作,cache miss時,在cache中分配一個空間,從下一級存儲讀取該數據到cache分配的這個空間,最後讀取該值。注意:對於Write-back模式,如果分配的這個位置原數據是dirty的,需要將該數據先寫回下一級存儲。

Write-allocate:寫操作,cache miss時,在cache中分配一個空間,將數據先寫入該位置,根據Write-back還是Write-through決定是否再寫入下一級存儲。注意:對於Write-back模式,如果分配的這個位置原數據是dirty的,需要將該數據先寫回下一級存儲。


下面爲參考網址給出的2個示例圖,第一個是Write-through Read-allocate,第二個是Write-back Read and Write-allocate

A Write-Through cache with No-Write Allocation

簡單總結一下該部分:Write-through和Write-back爲寫入cache的模式,區別是在寫cache時是否還同時寫下一級memory;allocate那堆只在cache miss時生效,負責分配cache空間給讀和寫中轉用;另外,dirty只發生在Write-back模式,需要額外進行一步回寫。
 

Cache基礎知識歸納總結

https://blog.csdn.net/u010959074/article/details/52051606

1、緩存行
a) 緩存行:CPU不再是按字節訪問內存,而是以64字節爲單位的塊(chunk)拿取,稱爲一個緩存行(cache line)。
b) 當程序運行的時間主要與內存訪問的次數相關時,Cache的影響很重要。
c) 內存被分割成主存塊(chunk)
d) 數據對齊。
2、L1和L2緩存
a) L1數據緩存,一個32KB的L1指令緩存,還有一個4MB大小L2數據緩存。L1緩存是處理器獨享的,L2緩存是成對處理器共享的。
b) L1 速度 > L2 速度
c) 計算機的計算數據需要從磁盤調度到內存,然後再調度到L2 Cache,再到L1 Cache,最後進CPU寄存器進行計算。
3、指令級別的併發
a) 指令級別的併發性:部分指令具有併發性,U/V兩條流水線。
4、緩存的關聯性
 
a) 緩存關聯性
b) 直接映射:每個內存塊只能映射到一個特定的緩存槽
c) N路組關聯(N-way set associative cache):每個內存塊能夠被映射到N路特定緩存槽中的任意一路。
d) 完全關聯(Fully associative cache):每個內存塊能夠被映射到任意一個緩存槽。操作效果上相當於一個散列表。
5、緩存行的爲共享
a) 緩存行的爲共享:當一個處理器改變了屬於它自己緩存中的一個值,其它處理器就再也無法使用它自己原來的值,因爲其對應的內存位置將被刷新(invalidate)到所有緩存。而且由於緩存操作是以緩存行而不是字節爲粒度,所有緩存中整個緩存行將被刷新!
b) volatile關鍵字
當變量被某個線程A修改值之後,其它線程比如B若讀取此變量的話,立刻可以看到原來線程A修改後的值
注:普通變量與volatile變量的區別是volatile的特殊規則保證了新值能立即同步到主內存,以及每次使用前可以立即從內存刷新,即一個線程修改了某個變量的值,其它線程讀取的話肯定能看到新的值;
6、硬件複雜性
a) 有些處理器上,L1緩存能夠併發處理兩路訪問,如果訪問是來自不同的存儲體(?),而對同一存儲體的訪問只能串行處理。而且處理器聰明的優化策略也會使你感到驚訝,比如在僞共享的例子中,以前在一些沒有微調的機器上運行表現並不良好,但我家裏的機器能夠對最簡單的例子進行優化來減少緩存刷新。


a) 程序的運行存在時間和空間上的局部性
前者是指只要內存中的值被換入緩存,今後一段時間內會被多次引用,後者是指該內存附近的值也被換入緩存。如果在編程中特別注意運用局部性原理,就會獲得性能上的回報。
比如C語言中應該儘量減少靜態變量的引用,這是因爲靜態變量存儲在全局數據段,在一個被反覆調用的函數體內,引用該變量需要對緩存多次換入換出,而如果是分配在堆棧上的局部變量,函數每次調用CPU只要從緩存中就能找到它了,因爲堆棧的重複利用率高。
再比如循環體內的代碼要儘量精簡,因爲代碼(就是指令?)是放在指令緩存裏的,而指令緩存都是一級緩存,只有幾K字節大小,如果對某段代碼需要多次讀取,而這段代碼又跨越一個L1緩存大小,那麼緩存優勢將蕩然無存。
b)關於CPU的流水線(pipeline)併發性簡單說說,
Intel Pentium處理器有兩條流水線U和V,每條流水線可各自獨立地讀寫緩存,所以可以在一個時鐘週期內同時執行兩條指令。但這兩條流水線不是對等的,U流水線可以處理所有指令集,V流水線只能處理簡單指令。
CPU指令通常被分爲四類,第一類是常用的簡單指令,像mov, nop, push, pop, add, sub, and, or, xor, inc, dec, cmp, lea,可以在任意一條流水線執行,只要相互之間不存在依賴性,完全可以做到指令併發。
第二類指令需要同別的流水線配合,像一些進位和移位操作,這類指令如果在U流水線中,那麼別的指令可以在V流水線併發運行,如果在V流水線中,那麼U流水線是暫停的。
第三類指令是一些跳轉指令,如cmp,call以及條件分支,它們同第二類相反,當工作在V流水線時才能通U流水線協作,否則只能獨佔CPU。
第四類指令是其它複雜的指令,一般不常用,因爲它們都只能獨佔CPU。
如果是彙編級別編程,要達到指令級別併發,必須要注重指令之間的配對。儘量使用第一類指令,避免第四類,還要在順序上減少上下文依賴。

a) 緩存行的開始點?數據對齊?
主存塊(chunk),如果是8字節對齊則,起始地址爲8的倍數。
http://www.cnblogs.com/bakari/archive/2012/08/27/2658956.html
Cache line alignment (cache對齊)
數據跨越兩個cache line,就意味着兩次load或者兩次store。如果數據結構是cache line對齊的,  就有可能減少一次讀寫。數據結構的首地址cache line對齊,意味着可能有內存浪費(特別是  數組這樣連續分配的數據結構),所以需要在空間和時間兩方面權衡。
對於普通代碼,內存邊界對齊也是有好處的,可以降低高速緩存(Cache)和內存交換數據的次數。主要問題是在於Cache本身是分成很多Cache-Line,每條Cache-Line具有一定的長度,比如一般來說L1 Cache每條Cache Line長度在32個字節或64個字節;而L2的會更大,比如64個字節或128個字節。用戶每次訪問地址空間中一個變量,如果不在Cache當中,那麼就需要從內存中先將數據調入Cache中.
比如現在有個變量 int x;佔用4個字節,它的起始地址是0x1234567F;那麼它佔用的內存範圍就在0x1234567F-0x12345682之間。如果現在Cache Line長度爲32個字節,那麼每次內存同Cache進行數據交換時,都必須取起始地址時32(0x20)倍數的內存位置開始的一段長度爲32的內存同Cache Line進行交換.   比如0x1234567F落在範圍0x12345660~0x1234567F上,但是0x12345680~0x12345682落在範圍 0x12345680~0x1234569F上,也就是說,爲了將4個字節的整數變量0x1234567F~0x12345682裝入Cache,我們必 須調入兩條Cache Line的數據。但是如果int x的起始地址按4的倍數對齊,比如是 0x1234567C~0x1234567F,那麼必然會落在一條Cache Line上,所以每次訪問變量x就最多只需要裝入一條Cache Line的數據了。比如現在一般的malloc()函數,返回的內存地址會已經是8字節對齊的,這個就是爲了能夠讓大部分程序有更好的性能。

b)多級緩存,級數設置?
1級速度要求最高的速度,2級次之,3級最次,3個級數就夠了,95%調用緩存,再多成本高。


c)L1與L2的合作?
http://coolshell.cn/articles/3236.html
計算機的計算數據需要從磁盤調度到內存,然後再調度到L2 Cache,再到L1 Cache,最後進CPU寄存器進行計算。
d) CPU的流水線?
http://blog.jobbole.com/40844/
I486擁有五級流水線。分別是:取指(Fetch),譯碼(D1, main decode),轉址(D2, translate),執行(EX, execute),寫回(WB)。某個指令可以在流水線的任何一級。
 
但是這樣的流水線有一個明顯的缺陷。對於下面的指令代碼,它們的功能是將兩個變量的內
容進行交換。
1
2
3

XOR a, b
XOR b, a
XOR a, b
從8086直到386處理器都沒有流水線。處理器一次只能執行一條指令。再這樣的架構下,上面的代碼執行並不會存在問題。
但是i486處理器是首個擁有流水線的x86處理器,它執行上面的代碼會發生什麼呢?當你一下去觀察很多指令在流水線中運行,你會覺得混亂,所以你需要回頭參考上面的圖。
第一步是第一條指令進入取指階段;然後在第二步第一條指令進入譯碼階段,同時第二條指令進入取指階段;第三步第一條指令進入轉址階段,第二條指令進入譯碼階段,第三條指令進入取指階段。但是在第四步會出現問題,第一條指令會進入執行階段,而其他指令卻不能繼續向前移動。第二條xor指令需要第一條xor指令計算的結果a,但是直到第一條指令執行完成纔會寫回。所以流水線的其他指令就會在當前流水級等待直到第一條指令的執行和寫回階段完成。第二條指令會等待第一條指令完成才能進入流水線下一級,同樣第三條指令也要等待第二條指令完成。
這個現象被稱爲流水線阻塞或者流水線氣泡。


e) 本機中的緩存大小
L1d cache:             12*32K  獨享
L1i cache:              12*32K獨享
L2 cache:              12*256K獨享
L3 cache:              30720K  一個物理cpu中所有內核共享
NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46
NUMA node1 CPU(s):     1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47
f )  L1、L2緩存行大小。
英特爾酷睿i7,酷睿, Atom和NetBurst, Core Solo和Pentium M處理器的L1,L2或L3緩存的高速緩存行是64個字節寬。


g)寫命中:
http://blog.csdn.net/opensure/article/details/46669337
當處理器將操作數寫回到一個內存緩存的區域時,它首先會檢查這個緩存的內存地址是否在緩存行中,如果不存在一個有效的緩存行,則處理器將這個操作數寫回到緩存,而不是寫回到內存,這個操作被稱爲寫命中。

----------------------------------------------------------------------------

術語 英文單詞 描述
共享變量 在多個線程之間能夠被共享的變量被稱爲共享變量。共享變量包括所有的實例變量,靜態變量和數組元素。他們都被存放在堆內存中,Volatile只作用於共享 變量。
內存屏障 Memory Barriers 是一組處理器指令,用於實現對內存操作的順序限制。
備註: In the Java Memory Model a volatile field has a store barrier inserted after a write to it and a load barrier inserted before a read of it.
緩衝行 Cache line 緩存中可以分配的最小存儲單位。處理器填寫緩存線時會加載整個緩存線,需要使用多個主內存讀週期。
原子操作 Atomic operations 不可中斷的一個或一系列操作。
緩存行填充 cache line fill 當處理器識別到從內存中讀取操作數是可緩存的,處理器讀取整個緩存行到適當的緩存(L1,L2,L3的或所有)
緩存命中 cache hit 如果進行高速緩存行填充操作的內存位置仍然是下次處理器訪問的地址時,處理器從緩存中讀取操作數,而不是從內存。
寫命中 write hit 當處理器將操作數寫回到一個內存緩存的區域時,它首先會檢查這個緩存的內存地址是否在緩存行中,如果不存在一個有效的緩存行,則處理器將這個操 作數寫回到緩存,而不是寫回到內存,這個操作被稱爲寫命中。
寫缺失 write misses the cache 一個有效的緩存行被寫入到不存在的內存區域。
 

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