【轉】cpu cache line 原理

 
參考:
一個講解Direct Mapped Cache很是深刻淺出的文章:
 
CPU cache
 
 
=============================================
 
整體認識
cpu的cache一般較大, 好比 128KB, 被劃分爲多個有固定大小的cache line, cache line一般是32Byte或64Byte.

CPU內部的cache種類, 至少有三種
1) 指令cache
2) 數據cache 一般有多級 multi-level
3) TLB 加速虛擬地址2物理地址轉換


cache entry (cache條目)
包含以下部分
1) cache line : 從主存一次copy的數據大小)
2) tag : 標記cache line對應的主存的地址
3) falg : 標記當前cache line是否invalid, 若是是數據cache, 還有是否dirty


cpu訪問主存的規律
1) cpu歷來都不直接訪問主存, 都是經過cache間接訪問主存
2) 每次須要訪問主存時, 遍歷一遍所有cache line, 查找主存的地址是否在某個cache line中.
3) 若是cache中沒有找到, 則分配一個新的cache entry, 把主存的內存copy到cache line中, 再從cache line中讀取.


cache中包含的cache entry條目有限, 因此, 必須有合適的cache淘汰策略
通常使用的是LRU策略.
將一些主存區域標記爲non-cacheble, 能夠提升cache命中率, 下降沒用的cache


回寫策略
cache中的數據更新後,須要回寫到主存, 回寫的時機有多種
1) 每次更新都回寫. write-through cache
2) 更新後不回寫,標記爲dirty, 僅當cache entry被evict時纔回寫
3) 更新後, 把cache entry送如回寫隊列, 待隊列收集到多個entry時批量回寫.


cache一致性問題
有兩種狀況可能致使cache中的數據過時
1) DMA, 有其餘設備直接更新主存的數據
2) SMP, 同一個cache line存在多個CPU各自的cache中. 其中一個CPU對其進行了更新.


cpu stall cpu失速
指的是當cache miss時(特別是read cache miss), cpu在等待數據從內存讀進去cache中期間, 沒事可作.
解決此問題的方法有
1) 超線程技術. CPU在硬件層面, 把一個CPU模擬成兩個CPU, 在上層看來是兩個CPU. 併發的執行兩個線程. 這樣當一個線程因cache miss在等待時, 另外一個線程能夠執行.


主存的一個地址, 須要被映射進哪一個cache line? (術語:Associativity)
根據映射策略的不一樣而不一樣


1) 最笨的, 一個地址可被映射進任意cache line (fully associative)
   帶來的問題是, 當尋找一個地址是否已經被cache時, 須要遍歷每個cache line來尋找, 這個代價不可接受.
   就像停車位能夠你們隨便停同樣, 停的時候簡單的, 找車的時候須要一個一個停車位的找了.
   你想下, cpu想知道一個地址是否已經在cache中了, 須要把所有cache line找一邊, 那該有多慢?


2) Direct Mapped Cache  (至關於1-way associative)
   這個就是至關於hash了, 每一個地址能被映射到的cache line是固定的. 
   每一個人的停車位是固定分配好的. 能夠直接找到.
   缺點是, 由於人多車少, 極可能幾我的爭用同一個車位, 致使cache 淘汰頻繁. 須要頻繁的從主存讀取數據到cache, 這個代價也較高.
   因爲cache中cache line的個數都是2的指數個. 那麼, hash算法就很簡單了, 不用取模, 直接把內存地址的某幾個bit位拿出來便可. 好比cache line有128(2^7)個, cache line的大小是32(2^5)字節, 
   那麼一個32位地址的 0~4位做爲cache line內部偏移, 5~11位做爲cache line的索引便可. 剩下的bit12~31做爲當前cache line的tag. tag的做用時, 當有另一個地址也映射到同一個cache line時, tag用來比較兩個地址是否是同一個地址. 畢竟同一個cache-line能夠對應的內存的位置很是多個的.


3) 2-way associative
   是fully associative和Direct Mapped Cache的折中.
   2-way, 每個人能夠有兩個停車位, 這樣當一個停車位被佔了的時候, 還有機會尋找另一個. 雖然人數衆多, 但同時來找停車位的人並很少. (至關於不少人的車在外面,沒有開回來)
   因此, 2-way associative近似的至關於有了2倍大小的cache, 使用Direct Mapped Cache策略.

cache-hash.jpg
注意, 這圖只統計了cache miss率, 很顯然full-associative是作好的. 可是full-associative致使的判斷一個地址是否在cache中的代價是很是昂貴的.因此, 生產環境通常都是2-way associative
======================================================

多線程變成中避免以及識別錯誤的共享變量方式 主要解決在SMP環境下cache line被頻繁刷新的的問題
Avoiding and Identifying False Sharing Among Threads
 
舉例:
// 以下代碼在SMP環境下存在cache頻繁刷新問題
double sum=0.0, sum_local[NUM_THREADS];
#pragma omp parallel num_threads(NUM_THREADS)
{
 int me = omp_get_thread_num();
 sum_local[me] = 0.0;

 #pragma omp for
 for (i = 0; i < N; i++)
 sum_local[me] += x[i] * y[i];

 #pragma omp atomic
 sum += sum_local[me];
}
由於sum_local數組是個全局變量, 多個線程都會訪問, 而且, 各個線程訪問的地方很接近, 會致使一個線程更新, 其餘CPU的cache line失效.
smp.jpg
 
解決該問題的方法是
1) 不一樣線程之間儘可能少的訪問全局變量, 儘可能使用線程局部變量.
2) 若是必定要訪問, 儘可能讓各個線程本身訪問的區域cacheline對齊.
3) 頻繁更新的存儲和不頻繁更新的存儲分開.
相關文章
相關標籤/搜索