吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

宋寶華:深入理解cache對寫好代碼至關重要

Linux閱碼場 ? 來源:Linux閱碼場 ? 作者:Linux閱碼場 ? 2022-12-06 10:38 ? 次閱讀

CACHE基礎

cache的掌握,對于Linux工程師(其他的非Linux工程師也一樣)寫出高效能代碼,以及優化Linux系統的性能是至關重要的。簡單來說,cache快,內存慢,硬盤更慢。在一個典型的現代CPU中比較接近改進的哈佛結構,cache的排布大概是這樣的:

45e28fda-74fa-11ed-8abf-dac502259ad0.png

L1速度> L2速度> L3速度> RAM

L1容量容量< L3容量< RAM

現代CPU,通常L1 cache的指令和數據是分離的。這樣可以實現2條高速公路并行訪問,CPU可以同時load指令和數據。當然,cache也不一定是一個core獨享,現代很多CPU的典型分布是這樣的,比如多個core共享一個L3。比如這臺的Linux里面運行lstopo命令:

45eb2f28-74fa-11ed-8abf-dac502259ad0.png

人們也常常稱呼L2cacheMLCMiddleLevel Cache,L3cacheLLCLast LevelCache。這些Cache究竟有多塊呢?我們來看看Intel的數據,具體配置:Intel i7-4770 (Haswell), 3.4 GHz (Turbo Boostoff), 22 nm. RAM: 32 GB (PC3-12800 cl11 cr2)

訪問延遲

45f763a6-74fa-11ed-8abf-dac502259ad0.png

數據來源:https://www.7-cpu.com/cpu/Haswell.html

由此我們可以知道,我們應該盡可能追求cache的命中率高,以避免延遲,最好是低級cache的命中率越高越好。

CACHE的組織

現代的cache基本按照這個模式來組織:SETWAYTAGINDEX,這幾個概念是理解Cache的關鍵。隨便打開一個數據手冊,就可以看到這樣的字眼:

45ffdf90-74fa-11ed-8abf-dac502259ad0.png

翻譯成中文就是4路(way)組(set)相聯,VIPT表現為(behave as)PIPT --這尼瑪什么鬼?cacheline的長度是64字節。

下面我們來想象一個16KB大小的cache,假設是4路組相聯,cacheline的長度是64字節。Cacheline的概念比較簡單,cache的整個替換是以行為單位的,一行64個字節里面讀了任何一個字節,其實整個64字節就進入了cache

比如下面兩段程序,前者的計算量是后者的8倍:

46080968-74fa-11ed-8abf-dac502259ad0.png

但是它的執行時間,則遠遠不到后者的8倍:

460f7fea-74fa-11ed-8abf-dac502259ad0.png

16KBcache4way的話,每個set包括4*64B,則整個cache分為16KB/64B/4 = 64set,也即26次方。當CPUcache里面讀數據的時候,它會用地址位的BIT6-BIT11來尋址setBIT0-BIT5cacheline內的offset

46162372-74fa-11ed-8abf-dac502259ad0.png

比如CPU訪問地址

0 000000 XXXXXX

或者

1 000000 XXXXXX

或者

YYYY 000000 XXXXXX

由于它們紅色的6位都相同,所以他們全部都會找到第0setcacheline。第0set里面有4way,之后硬件會用地址的高位如0,1YYYY作為tag,去檢索這4waytag是否與地址的高位相同,而且cacheline是否有效,如果tag匹配且cacheline有效,則cache命中。

所以地址YYYYYY000000XXXXXX全部都是找第0setYYYYYY000001XXXXXX全部都是找第1setYYYYYY111111XXXXXX全部都是找第63set。每個set中的4way,都有可能命中。

中間紅色的位就是INDEX,前面YYYY這些位就是TAG。具體的實現可以是用虛擬地址或者物理地址的相應位做TAG或者INDEX。如果用虛擬地址做TAG,我們叫VT;如果用物理地址做TAG,我們叫PT;如果用虛擬地址做INDEX,我們叫VI;如果用物理地址做TAG,我們叫PT。工程中碰到的cache可能有這么些組合:

VIVTVIPTPIPT

VIVT的硬件實現開銷最低,但是軟件維護成本高;PIPT的硬件實現開銷最高,但是軟件維護成本最低;VIPT介于二者之間,但是有些硬件是VIPT,但是behave as PIPT,這樣對軟件而言,維護成本與PIPT一樣。

VIVT的情況下,CPU發出的虛擬地址,不需要經過MMU的轉化,直接就可以去查cache

462121d2-74fa-11ed-8abf-dac502259ad0.png

而在VIPTPIPT的場景下,都涉及到虛擬地址轉換為物理地址后,再去比對cache的過程。VIPT如下:

4628e598-74fa-11ed-8abf-dac502259ad0.png

PIPT如下:

4631c078-74fa-11ed-8abf-dac502259ad0.png

從圖上看起來,VIVT的硬件實現效率很高,不需要經過MMU就可以去查cache了。不過,對軟件來說,這是個災難。因為VIVT有嚴重的歧義和別名問題。

歧義:一個虛擬地址先后指向兩個(或者多個)物理地址

別名:兩個(或者多個)虛擬地址同時指向一個物理地址

這里我們重點看別名問題。比如2個虛擬地址對應同一個物理地址,基于VIVT的邏輯,無論是INDEX還是TAG2個虛擬地址都是可能不一樣的(盡管他們的物理地址一樣,但是物理地址在cache比對中完全不摻和),這樣它們完全可能在2cacheline同時命中。

463b7a0a-74fa-11ed-8abf-dac502259ad0.png

由于2個虛擬地址指向1個物理地址,這樣CPU寫過第一個虛擬地址后,寫入cacheline1CPU讀第2個虛擬地址,讀到的是過時的cacheline2,這樣就出現了不一致。所以,為了避免這種情況,軟件必須寫完虛擬地址1后,對虛擬地址1對應的cache執行clean,對虛擬地址2對應的cache執行invalidate

PIPT完全沒有這樣的問題,因為無論多少虛擬地址對應一個物理地址,由于物理地址一樣,我們是基于物理地址去尋找和比對cache的,所以不可能出現這種別名問題。

46454332-74fa-11ed-8abf-dac502259ad0.png

那么VIPT有沒有可能出現別名呢?答案是有可能,也有可能不能。如果VI恰好對于PI,就不可能,這個時候,VIPT對軟件而言就是PIPT了:

VI=PI

PT=PT

那么什么時候VI會等于PI呢?這個時候我們來回憶下虛擬地址往物理地址的轉換過程,它是以頁為單位的。假設一頁是4K,那么地址的低12位虛擬地址和物理地址是完全一樣的。回憶我們前面的地址:

YYYYY000000XXXXXX

其中紅色的000000INDEX。在我們的例子中,紅色的6位和后面的XXXXXXcache內部偏移)加起來正好12位,所以這個000000經過虛實轉換后,其實還是000000的,這個時候VI=PIVIPT沒有別名問題。

我們原先假設的cache是:16KB大小的cache,假設是4路組相聯,cacheline的長度是64字節,這樣我們正好需要紅色的6位來作為INDEX。但是如果我們把cache的大小增加為32KB,這樣我們需要 32KB/4/64B=128=2^7,也即7位來做INDEX

YYYY0000000XXXXXX

這樣VI就可能不等于PI了,因為紅色的最高位超過了2^12的范圍,完全可能出現如下2個虛擬地址,指向同一個物理地址:

464b5a38-74fa-11ed-8abf-dac502259ad0.png

這樣就出現了別名問題,我們在工程里,可能可以通過一些辦法避免這種別名問題,比如軟件在建立虛實轉換的時候,把虛實轉換往2^13而不是2^12對齊,讓物理地址的低13位而不是低12位與物理地址相同,這樣強行繞開別名問題,下圖中,2個虛擬地址指向了同一個物理地址,但是它們的INDEX是相同的,這樣VI=PI,就繞開了別名問題。這通常是PAGE COLOURING技術中的一種技巧。

4652aa0e-74fa-11ed-8abf-dac502259ad0.png

如果這種PAGE COLOURING的限制對軟件仍然不可接受,而我們又想享受VIPTINDEX不需要經過MMU虛實轉換的快捷?有沒有什么硬件技術來解決VIPT別名問題呢?確實是存在的,現代CPU很多都是把L1 CACHE做成VIPT,但是表現地(behave as)像PIPT。這是怎么做到的呢?

這要求VIPTcache,硬件上具備alias detection的能力。比如,硬件知道YYYY0000000XXXXXX既有可能出現在第0000000,又可能出現在10000002set,然后硬件自動去比對這2set里面是否出現映射到相同物理地址的cacheline,并從硬件上解決好別名同步,那么軟件就完全不用操心了。

下面我們記住一個簡單的規則:

對于VIPT,如果cachesize除以WAY數,小于等于1page的大小,則天然VI=PI,無別名問題;

對于VIPT,如果cachesize除以WAY數,大于1page的大小,則天然VIPI,有別名問題;這個時候又分成2種情況:

  • 硬件不具備alias detection能力,軟件需要pagecolouring

  • 硬件具備alias detection能力,軟件把cache當成PIPT用。

比如cache大小64KB4WAYPAGE SIZE4K,顯然有別名問題;這個時候,如果cache改為16WAY,或者PAGE SIZE改為16K,不再有別名問題。為什么?感覺小學數學知識也能算得清

CACHE的一致性

Cache的一致性有這么幾個層面

1.一個CPUicachedcache的同步問題

2.多個CPU各自的cache同步問題

3.CPU與設備(其實也可能是個異構處理器,不過在Linux運行的CPU眼里,都是設備,都是DMA)的cache同步問題

465c51a8-74fa-11ed-8abf-dac502259ad0.png

先看一下ICACHEDCACHE同步問題。由于程序的運行而言,指令流的都流過icache,而指令中涉及到的數據流經過dcache。所以對于自修改的代碼(Self-Modifying Code)而言,比如我們修改了內存p這個位置的代碼(典型多見于JIT compiler),這個時候我們是通過store的方式去寫的p,所以新的指令會進入dcache。但是我們接下來去執行p位置的指令的時候,icache里面可能命中的是修改之前的指令。

4665f582-74fa-11ed-8abf-dac502259ad0.png

所以這個時候軟件需要把dcache的東西clean出去,然后讓icache invalidate,這個開銷顯然還是比較大的。

但是,比如ARM64N1處理器,它支持硬件的icache同步,詳見文檔:The Arm Neoverse N1 Platform: Building Blocks for the Next-Gen Cloud-to-Edge Infrastructure SoC

466fd3d6-74fa-11ed-8abf-dac502259ad0.png

特別注意畫紅色的幾行。軟件維護的成本實際很高,還涉及到icache的invalidation向所有核廣播的動作。

接下來的一個問題就是多個核之間的cache同步。下面是一個簡化版的處理器,CPU_AB共享了一個L3CPU_CCPU_D共享了一個L3。實際的硬件架構由于涉及到NUMA,會比這個更加復雜,但是這個圖反映層級關系是足夠了。

467c37f2-74fa-11ed-8abf-dac502259ad0.png

比如CPU_A讀了一個地址p的變量?CPU_BCD又讀,難道B,C,D又必須從RAM里面經過L3,L2,L1再讀一遍嗎?這個顯然是沒有必要的,在硬件上,cachesnooping控制單元,可以協助直接把CPU_Ap地址cache拷貝到CPU_BCDcache

46827bc6-74fa-11ed-8abf-dac502259ad0.png

這樣A-B-C-D都得到了相同的p地址的棕色小球。

假設CPU B這個時候,把棕色小球寫成紅色,而其他CPU里面還是棕色,這樣就會不一致了:

469cff1e-74fa-11ed-8abf-dac502259ad0.png

這個時候怎么辦?這里面顯然需要一個協議,典型的多核cache同步協議有MESIMOESIMOESI相對MESI有些細微的差異,不影響對全局的理解。下面我們重點看MESI協議。

MESI協議定義了4種狀態:

MModified: 當前cache的內容有效,數據已被修改而且與內存中的數據不一致,數據只在當前cache里存在;類似RAM里面是棕色球,B里面是紅色球(CACHERAM不一致),ACD都沒有球。

46a4f5c0-74fa-11ed-8abf-dac502259ad0.png

EExclusive):當前cache的內容有效,數據與內存中的數據一致,數據只在當前cache里存在;類似RAM里面是棕色球,B里面是棕色球(RAMCACHE一致),ACD都沒有球。

46aef2dc-74fa-11ed-8abf-dac502259ad0.png

SShared):當前cache的內容有效,數據與內存中的數據一致,數據在多個cache里存在。類似如下圖,在CPU A-B-C里面cache的棕色球都與RAM一致。

46b6fc2a-74fa-11ed-8abf-dac502259ad0.png

IInvalid): 當前cache無效。前面三幅圖里面cache沒有球的那些都是屬于這個情況。

然后它有個狀態機

46cb5cf6-74fa-11ed-8abf-dac502259ad0.png

這個狀態機比較難記,死記硬背是記不住的,也沒必要記,它講的cache原先的狀態,經過一個硬件在本cache或者其他cache的讀寫操作后,各個cache的狀態會如何變遷。所以,硬件上不僅僅是監控本CPUcache讀寫行為,還會監控其他CPU的。只需要記住一點:這個狀態機是為了保證多核之間cache的一致性,比如一個干凈的數據,可以在多個CPUcache share,這個沒有一致性問題;但是,假設其中一個CPU寫過了,比如A-B-C本來是這樣:

46b6fc2a-74fa-11ed-8abf-dac502259ad0.png

然后B被寫過了:

46dc1942-74fa-11ed-8abf-dac502259ad0.png

這樣ACcache實際是過時的數據,這是不允許的。這個時候,硬件會自動把ACcache invalidate掉,不需要軟件的干預,AC其實變地相當于不命中這個球了:

46e4f85a-74fa-11ed-8abf-dac502259ad0.png

這個時候,你可能會繼續問,如果C要讀這個球呢?它目前的狀態在B里面是modified的,而且與RAM不一致,這個時候,硬件會把紅球clean,然后BCRAM變地一致,BC的狀態都變化為SShared):

46eed9e2-74fa-11ed-8abf-dac502259ad0.png

這一系列的動作雖然由硬件完成,但是對軟件而言不是免費的,因為它耗費了時間。如果編程的時候不注意,引起了硬件的大量cache同步行為,則程序的效率可能會急劇下降。

為了讓大家直觀感受到這個cache同步的開銷,下面我們寫一個程序,這個程序有2個線程,一個寫變量,一個讀變量:

46f8044a-74fa-11ed-8abf-dac502259ad0.png

這個程序里,xy都是cacheline對齊的,這個程序的thread1的寫,會不停地與thread2的讀,進行cache同步。

它的執行時間為:

$ time ./a.out 
real  0m3.614s
user  0m7.021s
sys0m0.004s

它在2CPU上的userspace共運行了7.021秒,累計這個程序從開始到結束的對應真實世界的時間是3.614秒(就是從命令開始到命令結束的時間)。

如果我們把程序改一句話,把thread2里面的c = x改為c = y,這樣2個線程在2CPU運行的時候,讀寫的是不同的cacheline,就沒有這個硬件的cache同步開銷了:

46fe4120-74fa-11ed-8abf-dac502259ad0.png

它的運行時間:

$ time ./b.out 
real  0m1.820s
user  0m3.606s
sys0m0.008s

現在只需要1.8秒,幾乎減小了一半。

感覺前面那個a.out,雙核的幫助甚至都不大。如果我們改為單核跑呢?

$ time taskset -c 0 ./a.out 
real  0m3.299s
user  0m3.297s
sys0m0.000s

它單核跑,居然只需要3.299秒跑完,而雙核跑,需要3.614s跑完。單核跑完這個程序,甚至比雙核還快,有沒有驚掉下巴?!!!因為單核里面沒有cache同步的開銷。

下一個cache同步的重大問題,就是設備與CPU之間。如果設備感知不到CPUcache的話(下圖中的紅色數據流向不經過cache),這樣,做DMA前后,CPU就需要進行相關的cachecleaninvalidate的動作,軟件的開銷會比較大。

471a1c1a-74fa-11ed-8abf-dac502259ad0.png

這些軟件的動作,若我們在Linux編程的時候,使用的是streaming DMA APIs的話,都會被類似這樣的API自動搞定:

dma_map_single()
dma_unmap_single()
dma_sync_single_for_cpu()
dma_sync_single_for_device()
dma_sync_sg_for_cpu()
dma_sync_sg_for_device()

如果是使用的dma_alloc_coherent() API呢,則設備和CPU之間的buffercache一致的,不需要每次DMA進行同步。對于不支持硬件cache一致性的設備而言,很可能dma_alloc_coherent()會把CPU對那段DMA buffer的訪問設置為uncachable的。

這些API把底層的硬件差異封裝掉了,如果硬件不支持CPU和設備的cache同步的話,延時還是比較大的。那么,對于底層硬件而言,更好的實現方式,應該仍然是硬件幫我們來搞定。比如我們需要修改總線協議,延伸紅線的觸角:

47200418-74fa-11ed-8abf-dac502259ad0.png

當設備訪問RAM的時候,可以去snoop CPUcache

  • 如果做內存到外設的DMA,則直接從CPUcachemodified的數據;

  • 如果做外設到內存的DMA,則直接把CPUcache invalidate掉。

這樣,就實現硬件意義上的cache同步。當然,硬件的cache同步,還有一些其他方法,原理上是類似的。注意,這種同步仍然不是免費的,它仍然會消耗bus cycles的。實際上,cache的同步開銷還與距離相關,可以說距離越遠,同步開銷越大,比如下圖中AB的同步開銷比AC小。

467c37f2-74fa-11ed-8abf-dac502259ad0.png

對于一個NUMA服務器而言,跨NUMAcache同步開銷顯然是要比NUMA內的同步開銷大。

意識到CACHE的編程

通過上一節的代碼,讀者應該意識到了cache的問題不處理好,程序的運行性能會急劇下降。所以意識到cache的編程,對程序員是至關重要的。

從CPU流水線的角度講,任何的內存訪問延遲都可以簡化為如下公式:

Average Access Latency = Hit Time + Miss Rate × Miss Penalty

cache miss會導致CPU的stall狀態,從而影響性能。現代CPU的微架構分了frontend和backend。frontend負責fetch指令給backend執行,backend執行依賴運算能力和Memory子系統(包括cache)延遲。

4731e58e-74fa-11ed-8abf-dac502259ad0.png

backend執行中訪問數據導致的cache miss會導致backend stall,從而降低IPC(instructions per cycle)。減小cache的miss,實際上是一個軟硬件協同設計的任務。比如硬件方面,它支持預取prefetch,通過分析cache miss的pattern,硬件可以提前預取數據,在流水線需要某個數據前,提前先取到cache,從而CPU流水線跑到需要它的時候,不再miss。當然,硬件不一定有那么聰明,也許它可以學會一些簡單的pattern。但是,對于復雜的無規律的數據,則可能需要軟件通過預取指令,來暗示CPU進行預取。

cache預取

比如在ARM處理器上就有一條指令叫pld,prefetch可以用pld指令:

static inline void prefetch(const void *ptr)
{
        __asm__ __volatile__(
                "pld	%a0"
                :: "p" (ptr));
}

眼見為實,我們隨便從Linux內核里面找一個commit:

474ee8f0-74fa-11ed-8abf-dac502259ad0.png

因為我們從WiFi收到了一個skb,我們很快就要訪問這個skb里面的數據來進行packet的分類以及交給IP stack處理了,不如我們先prefetch一下,這樣后面等需要訪問這個skb->data的時候,流水線可以直接命中cache,從而不打斷。

預取的原理有點類似今天星期五,咱們在上海office,下周一需要北京分公司的人來上海office開會。于是,我們通知北京office的人周末坐飛機過來,這樣周一開會的時候就不必等他們了。不預取的情況下,會議開始后,再等北京的人飛過來,會導致stall狀態。

任何東西最終還是要落實到代碼,talk is cheap,show me the code。下面這個是經典的二分查找法代碼,這個代碼是網上抄的。

47697ee0-74fa-11ed-8abf-dac502259ad0.png

特別留意ifdef DO_PREFETCH包著的代碼,它提前預取了下次的中間值。我們來對比下,不預取和預取情況下,這個同樣的代碼執行時間的差異。先把cpufreq的影響盡可能關閉掉,設置為performance:

barry@barry-HP-ProBook-450-G7:~$ sudo cpupower frequency-set 
--governor performance
Setting cpu: 0
Setting cpu: 1
Setting cpu: 2
Setting cpu: 3
Setting cpu: 4
Setting cpu: 5
Setting cpu: 6
Setting cpu: 7

然后我們來對比差異:

4787486c-74fa-11ed-8abf-dac502259ad0.png

開啟prefetch執行時間大約10s, 不prefetch的情況下,11.6s執行完成,性能提升大約14%,所以周末坐飛機太重要了!

現在我們來通過基于perf的pmu-tools(下載地址:https://github.com/andikleen/pmu-tools),對上面的程序進行topdown分析,分析的時候,為了盡可能減小其他因子的影響,我們把程序通過taskset運行到CPU0。

先看不prefetch的情況,很明顯,程序是backend_bound的,其中DRAM_Bound占比大,達到75.8%。

47a3f2fa-74fa-11ed-8abf-dac502259ad0.png

開啟prefetch的情況呢?程序依然是backend_bound的,其中,backend bound的主體依然是DRAM_Bound,但是比例縮小到了60.7%。

47de8f64-74fa-11ed-8abf-dac502259ad0.png

DRAM_Bound主要對應cycle_activity.stalls_l3_miss事件,我們通過perf stat來分別進行搜集:

47faeaa6-74fa-11ed-8abf-dac502259ad0.png

我們看到,執行prefetch情況下,指令的條數明顯多了,但是它的insn per cycle變大了,所以總的時間cycles反而減小。其中最主要的原因是cycle_activity.stalls_l3_miss變小了很多次。

這個時候,我們可以進一步通過錄制mem_load_retired.l3_miss來分析究竟代碼哪里出了問題,先看noprefetch情況:

48202f5a-74fa-11ed-8abf-dac502259ad0.png

焦點在main函數:

483765c6-74fa-11ed-8abf-dac502259ad0.png

繼續annotate一下:

484c80dc-74fa-11ed-8abf-dac502259ad0.png

明顯問題出在array[mid] < key這句話這里。做prefetch的情況下呢?

487286f6-74fa-11ed-8abf-dac502259ad0.png

main的占比明顯變小了(99.93% -> 80.00%):

488c5b26-74fa-11ed-8abf-dac502259ad0.png

繼續annotate一下:

489f3480-74fa-11ed-8abf-dac502259ad0.png

熱點被分散了,預取緩解了Memory_Bound的情況。

避免false sharing

前面我們提到過,數據如果在一個cacheline,被多核訪問的時候,多核間運行的cache一致性協議,會導致cacheline在多核間的同步。這個同步會有很大的延遲,是工程里著名的false sharing問題。

比如下面一個結構體

structs
{
inta;
intb;
}

如果1個線程讀寫a,另外一個線程讀寫b,那么兩個線程就有機會在不同的核,于是產生cacheline同步行為的來回顛簸。但是,如果我們把a和b之間padding一些區域,就可以把這兩個纏繞在一起的人拉開:

struct s
{
    int a;
charpadding[cacheline_size-sizeof(int)];
    int b;
}

因此,在實際的工程中,我們經常看到有人對數據的位置進行移位,或者在2個可能引起false sharing的數據間填充數據進行padding。這樣的代碼在內核不甚枚舉,我們隨便找一個:

48c25f28-74fa-11ed-8abf-dac502259ad0.png

它特別提到在tw_count后面60個字節(L1_CACHE_BYTES - sizeof(atomic_t))的padding,從而避免false sharing:

48e18272-74fa-11ed-8abf-dac502259ad0.png

下面這個則是通過移動結構體內部成員的位置,相關數據的cacheline分開的:

49024296-74fa-11ed-8abf-dac502259ad0.png

這個改動有明顯的性能提升,最高可達9.9%。代碼里面也有明顯地注釋,usage和parent原先靠地太近,一個頻繁寫,一個頻繁讀。移開了2邊互相不打架了:

49245994-74fa-11ed-8abf-dac502259ad0.png

把理論和代碼能對上的感覺真TNND爽。無論是996,還是007,都必須留些時間來思考,來讓理論和實踐結合,否則,就變成漫無目的的內卷,這樣一定會卷輸的。內卷并不可悲,可悲的是卷不贏別人。

審核編輯 :李倩

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux系統
    +關注

    關注

    4

    文章

    596

    瀏覽量

    27510
  • Cache
    +關注

    關注

    0

    文章

    129

    瀏覽量

    28435
  • 代碼
    +關注

    關注

    30

    文章

    4828

    瀏覽量

    69058

原文標題:宋寶華:深入理解cache對寫好代碼至關重要

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    抗震與防震的區別是什么?

    在保障各類設施安全穩定運行的過程中,抗震與防震是兩個重要概念,它們相輔相成,卻又有著明顯區別。尤其在如半導體制造潔凈車間這類對環境穩定性要求極高的場景下,深入理解兩者差異至關重要
    的頭像 發表于 01-23 14:41 ?99次閱讀
    抗震與防震的區別是什么?

    深入理解C語言:循環語句的應用與優化技巧

    能讓你的代碼更加簡潔明了,還能顯著提升程序執行效率。本文將詳細介紹C語言中的三種常見循環結構——while循環、for循環和do...while循環,帶你深入理解
    的頭像 發表于 12-07 01:11 ?251次閱讀
    <b class='flag-5'>深入理解</b>C語言:循環語句的應用與優化技巧

    深入理解 Llama 3 的架構設計

    最新的自然語言處理(NLP)技術和深度學習算法,旨在提供更加自然、流暢和智能的對話體驗。 1. 核心組件 Llama 3的架構設計可以分為以下幾個核心組件: 1.1 預處理模塊 預處理模塊負責將原始文本數據轉換為模型可以理解的格式。這包括文本清洗
    的頭像 發表于 10-27 14:41 ?642次閱讀

    CCTV《對話》傳音:在非洲書寫中國品牌的力量

    對于中非未來合作的展望,阿里夫慷慨良多:“不要為了短期利益出賣未來,這一點至關重要。我們要深入理解和尊重非洲的本土文化,并始終如一地踐行企業社會責任。
    的頭像 發表于 09-10 16:37 ?368次閱讀
    CCTV《對話》傳音:在非洲書寫中國品牌的力量

    深入理解FPD-link III ADAS解串器HUB產品

    電子發燒友網站提供《深入理解FPD-link III ADAS解串器HUB產品.pdf》資料免費下載
    發表于 09-06 09:58 ?1次下載
    <b class='flag-5'>深入理解</b>FPD-link III ADAS解串器HUB產品

    無刷電機驅動芯片方案的選擇至關重要

    在當今科技飛速發展的時代,無刷電機因其高效、低噪、長壽命等顯著優勢,在眾多領域得到了廣泛應用,從工業自動化到智能家居,從電動汽車到航空航天。而在無刷電機系統中,驅動芯片方案的選擇至關重要,它直接影響
    的頭像 發表于 09-05 17:28 ?728次閱讀

    技術干貨驛站 ▏深入理解C語言:掌握常量,讓你的代碼更加穩固高效!

    在C語言的世界中,常量是一種不可忽視的元素。無論你是在編寫簡單的代碼,還是構建復雜的系統,常量都能為你的程序帶來更高的穩定性和可靠性。在這篇文章中,我們將深入探討C語言中的常量,從整數常量到字符串
    的頭像 發表于 08-29 13:59 ?3040次閱讀
    技術干貨驛站 ▏<b class='flag-5'>深入理解</b>C語言:掌握常量,讓你的<b class='flag-5'>代碼</b>更加穩固高效!

    錫焊原理解析:深入理解電子產品制造的核心工藝

    探索焊接技術在精密電子工程中的重要性和創新,從基礎元件的連接到現代焊接技術的進展,深入了解焊接材料的選擇與焊接技術的分類。本文提供了對錫焊原理的深入分析,揭示了高質量電子產品制造的關鍵因素。
    的頭像 發表于 08-12 15:03 ?870次閱讀
    錫焊原<b class='flag-5'>理解</b>析:<b class='flag-5'>深入理解</b>電子產品制造的核心工藝

    夏季雷雨頻繁,新能源車輛車載充電機與整車防水設計至關重要

    車載充電機(On-Board Charger,OBC)與車載直流轉換器(DC-DC Converter)作為新能源汽車上至關重要的零部件,需要有特殊的防水處理。
    的頭像 發表于 07-30 09:07 ?397次閱讀
    夏季雷雨頻繁,新能源車輛車載充電機與整車防水設計<b class='flag-5'>至關重要</b>

    技術干貨驛站 ▏深入理解C語言:掌握程序結構知識

    在計算機編程的世界中,C語言被廣泛認可為一門強大而高效的編程語言,其簡潔的語法和直接的指令使得它成為了許多程序員的首選。了解C語言的程序結構和基本語法對于初學者來說至關重要。從一個簡單
    的頭像 發表于 07-27 08:45 ?1540次閱讀
    技術干貨驛站 ▏<b class='flag-5'>深入理解</b>C語言:掌握程序結構知識

    深入理解FFmpeg閱讀體驗》

    一、編譯X264 H.264是ITU(International Telecommunication Union,國際通信聯盟)和MPEG(Motion Picture Experts Group,運動圖像專家組)聯合制定的視頻編碼標準。而X264是一個開源的H.264/MPEG-4 AVC視頻編碼函數庫,是最好的有損視頻編碼器之一。 先直接從網絡(http://download.videolan.org/pub/videolan/x264/snapshots/)獲取X264源碼。考慮到版本關系,本文我下載的是x264-snapshot-20180430-2245-stable.tar.bz2。 tar -vxf x264-snapshot-20180430-2245-stable.tar.bz2 mkdir x264 手動創建的X264文件夾用于存放編譯后的X264庫。執行如下命令: ./configure --host=aarch64-linux --prefix=/home/x264 --enable-shared --disable-asm --enable-static --cross-prefix=aarch64-linux-gnu- 之后執行make make install完成x264庫的交叉編譯。生成的文件信息如下: root@EliteDesk800:~/x264/lib$ ls libx264.solibx264.so.152pkgconfig root@EliteDesk800:~/x264/lib$ file * libx264.so:symbolic link to libx264.so.152 libx264.so.152: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=01dd733d65c98eb894b4cdd41216259543ec8405, with debug_info, not stripped pkgconfig:directory 二、編譯FFmpeg 首先從FFmpeg官方網站http://ffmpeg.org/download.html上下載FFmpeg源碼。 tar -vxf ffmpeg-snapshot.tar.bz2 mkdir ffmpeg_install 其中ffmpeg_install文件夾用于保存生成的文件。執行如下命令: ./configure --prefix=/home/ffmpeg_install --enable-cross-compile --arch=arm64 --target-os=linux --cc=aarch64-linux-gnu-gcc --disable-x86asm --cross-prefix=aarch64-linugnu---pkg-config=/usr/bin/pkg-config --pkg-config=/usr/bin/pkg-config主要用于解決ERROR: x264 not found using pkg-config問題,網上很多解決方法都不靠譜。 之后執行make make install完成ffmpeg的交叉編譯。 生成的文件信息如下: root@EliteDesk800:~/ffmpeg$ file ../ffmpeg_install/bin/* ../ffmpeg_install/bin/ffmpeg:ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=b32285f11866f79dd499330849a9b3195ea0e446, stripped ../ffmpeg_install/bin/ffprobe: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=5d3fa4ea21ad6c4395bbaf134b915190799305b2, stripped
    發表于 04-16 22:54

    深入理解 FPGA 的基礎結構

    轉載地址:https://zhuanlan.zhihu.com/p/506828648 文章很詳細的介紹了FPGA的基礎結構,能更直觀的理解內部結構原理。對深入學習很有幫助。 以下是正文: 這一段
    發表于 04-03 17:39

    推拉力測試機在各種工業應用中,扮演著至關重要的角色

    推拉力測試機是一種精密設備,用于測量材料、組件或產品的抗拉強度、抗壓強度和撕裂強度等力學性能。在各種工業應用中,推拉力測試機扮演著至關重要的角色,確保產品質量和安全。1.汽車行業:推拉力測試機在
    的頭像 發表于 03-28 17:26 ?457次閱讀
    推拉力測試機在各種工業應用中,扮演著<b class='flag-5'>至關重要</b>的角色

    深入理解數據備份的關鍵原則:應用一致性與崩潰一致性的區別

    深入理解數據備份的關鍵原則:應用一致性與崩潰一致性的區別 在數字化時代,數據備份成為了企業信息安全的核心環節。但在備份過程中,兩個關鍵概念——應用一致性和崩潰一致性,常常被誤解或混淆。本文旨在闡明
    的頭像 發表于 03-11 11:29 ?1011次閱讀
    <b class='flag-5'>深入理解</b>數據備份的關鍵原則:應用一致性與崩潰一致性的區別

    成為Istio專家,開啟云原生應用之旅!

    ICA (Istio Certified Associate)認證考試展示了對Istio原則、術語和最佳實踐的深入理解,以便建立Istio。這對于在當今日益復雜的微服務計算環境中工作至關重要
    的頭像 發表于 02-21 15:11 ?526次閱讀
    成為Istio專家,開啟云原生應用之旅!
    做生意怕路冲吗| 做生意用的 风水上最好的尺寸有 做生意门朝向什么方向 | 大发888开户大发娱乐权威吗| 百家乐官网怎么玩呀| 太阳百家乐官网路单生| 威尼斯人娱乐城信誉lm0| 澳门百家乐官网皇冠网| 百家乐视频游戏注册| 最好的棋牌游戏| 百家乐官网那里玩| 韩国百家乐的玩法技巧和规则 | 百家乐官网与龙虎斗怎么玩| 玩百家乐秘诀| 网络轮盘| 顶级赌场官方直营网| 百家乐官网庄闲统计数| 太阳城娱乐网址| 百家乐官网庄家必赢诀窍| 百家乐送现金200| 百家乐官网赢钱海立方| 如何玩百家乐游戏| 百家乐官网风云人物| 百家乐赢的秘诀| 永利高网址| 网上百家乐哪里好| 贵阳市| 百家乐真人游戏网上投注 | 网上百家乐官网危险| 百家乐偷吗| 金道百家乐官网游戏| 尊龙百家乐娱乐平台| 网上百家乐官网如何作假| 百家乐路单走势图| 至尊百家乐官网节目单| 百家乐玩法说| 真人百家乐官网国际第一品牌| 大发888官网下载| 投真钱百家乐官网必输吗| 马德里百家乐的玩法技巧和规则| 百家乐官网网上投注文章| 大发888官|