【1024程序員節獻禮】鯤鵬性能優化十板斧(五)——應用程序性能調優

      網友投稿 1406 2025-04-02

      特戰隊六月底成立,至今百日有余,恰逢1024程序員節,遂整理此文,獻禮致敬!希望能為廣大在鯤鵬處理器上開發軟件、性能調優的程序員們,提供一點幫助。從今天開始,將陸續推出性能調優專題文章。

      1 應用程序調優

      1.1? 調優簡介

      1.2? 優化方法

      1.1 調優簡介

      應用程序部署到鯤鵬服務器上以后,需要結合芯片和服務器的特點優化代碼性能,使硬件能力得到充分發揮。本章列舉幾個典型場景,涉及鎖、編譯器配置、Cacheline、緩沖機制等優化。

      1.2 優化方法

      1.2.1 優化編譯選項,提升程序性能

      原理

      C/C++代碼在編譯時,gcc編譯器將源碼翻譯成CPU可識別的指令序列,寫入可執行程序的二進制文件中。CPU在執行指令時,通常采用流水線的方式并行執行指令,以提高性能,因此指令執行順序的編排將對流水線執行效率有很大影響。通常在指令流水線中要考慮:執行指令計算的硬件資源數量、不同指令的執行周期、指令間的數據依賴等等因素。我們可以通過通知編譯器,程序所運行的目標平臺(CPU)指令集、流水線,來獲取更好的指令序列編排。在gcc 9.1.0版本,支持了鯤鵬處理器所兼容的armv8指令集、tsv110流水線。

      修改方式

      l?? 在Euler系統中使用HCC編譯器,可以在CFLAGS和CPPFLAGS里面增加編譯選項:

      -mtune=tsv110 -march=armv8-a

      l?? 在其它操作系統中,可以升級GCC版本到9.10,并在CFLAGS和CPPFLAGS里面增加編譯選項:

      -mtune=tsv110 -march=armv8-a

      1.2.2 文件緩沖機制選擇

      原理

      內存訪問速度要高于磁盤,應用程序在讀寫磁盤時,通常會經過一些緩存,以減少對磁盤的直接訪問,如下圖所示:

      clib buffer:clib buffer是用戶態的一種數據緩沖機制,在啟用clib buffer的情況下,數據從應用程序的buffer拷貝至clib buffer后,并不會立即將數據同步到內核,而是緩沖到一定規模或者主動觸發的情況下,才會同步到內核;當查詢數據時,會優先從clib buffer查詢數據。這個機制能減少用戶態和內核態的切換(用戶態切換內核態占用一定資源)。

      PageCache:PageCache是內核態的一種文件緩存機制,用戶在讀寫文件時,先操作PageCache,內核根據調度機制或者被應用程序主動觸發時,會將數據同步到磁盤。PageCache機制能減少磁盤訪問。

      修改方式

      應用程序根據自己的業務特點選擇合適的文件讀寫方式:

      l?? fread/fwrite函數使用了clib buffer緩存機制,而read/write并沒有使用,因此fread/fwrite比read/write多一層內存拷貝,即從應用程序buffer至clib buffer的拷貝,但是fread/fwrite比read/write有更少的系統調用。因此對于每次讀寫字節數較大的操作,內存拷貝比系統調用占用更多資源,可以使用read/write來減少內存拷貝;對于每次讀寫字節數較少的操作,系統調用比內存拷貝占用更多資源,建議使用fread/ fwrite來減少系統調用次數。

      l?? O_DIRECT模式沒有使用PageCache,因此少了一層內存拷貝,但是因為沒有緩沖導致每次都是從磁盤里面讀取數據。

      O_DIRECT主要適用場景為:應用程序有自己的緩沖機制;數據讀寫一次后,后面不再從磁盤讀這個數據。

      1.2.3 執行結果緩存

      原理

      對于相同的輸入,應用軟件經過計算后,有相同的輸出,可以將運算結果保存,在下次有相同的輸入時,返回上次執行的結果。

      修改方式

      目前部分開源軟件已經實現這種機制,舉例如下:

      1.???????? Nginx緩沖

      基于局部性原理,Nginx使用proxy_cache_path等參數將請求過的內容在本地內存建立一個副本,這樣對于緩存中的文件不用去后端服務器去取。

      2.???????? JIT編譯

      JIT(Just-In-Time)編譯,將輸入文件轉為機器碼。為了提升效率,轉換后的機器碼被緩存在內存,這樣相同的輸入(如JAVA程序的字節碼)不用重新翻譯,直接返回緩存中的內容。如果發現JAVA虛擬機的C1 Compiler/C2 Compiler線程的CPU占用比較多,可能是JIT緩沖不夠,可以增加JAVA虛擬機ReservedCodeCacheSize參數。

      1.2.4 減少內存拷貝

      原理

      基于數據流分析,發現并減少內存拷貝次數,能降低CPU使用率,并減少內存帶寬占用。

      修改方式

      減少內存拷貝要基于業務邏輯進行分析,這里例舉幾種減少內存拷貝的實現機制:

      l?? 樣例一:使用sendfile代替send/sendto/write等函數將文件發送給對端

      如下兩條語句將文件發送給對端,一般會有4次內存拷貝

      ssize_t read (int fd, void *buf, size_t count);

      ssize_t send (int s, const void * buf, size_t len, int flags);

      ??????????? read函數一般有2次內存拷貝: DMA將數據搬運到內核的PageCache;內核將數據搬運到應用態的buf。

      ??????????? send函數一般有2次內存拷貝: write函數將應用態的buf的拷貝到內核;DMA將數據搬運到網卡。

      使用如下函數實現只需要兩次內存拷貝:

      ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

      內核通過 DMA將文件搬運到緩存(一次內存拷貝),然后把緩存的描述信息(位置和長度)傳遞給TCP/IP協議棧,內核在通過DMA將緩沖搬運到網卡(第二次內存拷貝)。

      除了修改代碼,部分開源軟件已經支持這個特性,如Nginx可以通過sendfile on參數打開這個功能。

      l?? 樣例二:進程間通信使用共享內存代替socket/pipe通信

      內存共享方式可以讓多個進程操作同樣的內存區域,相比socket通信的的方式,內存拷貝少。應用程序可以使用shmget等函數實現進程間通信

      1.2.5 鎖優化

      原理

      自旋鎖和CAS指令都是基于原子操作指令實現,當應用程序在執行原子操作失敗后,并不會釋放CPU資源,而是一直循環運行直到原子操作執行成功為止,導致CPU資源浪費。如下圖代碼的黃色部分是一個循環等待過程:

      修改方式

      可以通過perf top分析占用CPU資源靠前的函數,如果鎖的申請和釋放在5%以上,可以考慮優化鎖的實現,修改思路如下:

      1.???????? 大鎖變小鎖:并發任務高的場景下,如果系統中存在唯一的全局變量,那么每個CPU core都會申請這個全局變量對應的鎖,導致這個鎖的爭搶嚴重。可以基于業務邏輯,為每個CPU core或者線程分配對應的資源。

      2.???????? 使用ldaxr+stlxr兩條指令實現原子操作時,可以同時保證內存一致性,而ldxr+stxr指令并不能保存內存一致性,從而需要內存屏障指令(dmb ish)配合來實現內存一致性。從測試情況看,ldaxr+stlxr指令比ldxr+stxr+dmb ish指令的性能高。

      3.???????? 減少線程并發數:參考2.3.5 調整線程并發數章節。

      4.???????? 對鎖變量使用Cacheline對齊:對于高頻訪問的鎖變量,實際是對鎖變量進行高頻的讀寫操作,容易發生偽共享問題。具體優化可以參考5.2.7 Cacheline 優化章節。

      5.???????? 優化代碼中原子操作的實現。下圖代碼為某軟件的代碼實現:

      從函數調用邏輯上看,在while循環會重復執行原子讀、變量加以及原子寫入操作,代碼語句多。優化思路:使用atomic_add_return指令替換這個代碼流程,簡化指令,提高性能。替換后的代碼如下圖:

      1.2.6 使用jemalloc優化內存分配

      原理

      jemalloc是一款內存分配器,與其它內存分配器(glibc)相比,其最大優勢在于多線程場景下內存分配性能高以及內存碎片減少。充分發揮鯤鵬芯片多核多并發優勢,推薦業務應用代碼使用jemalloc進行內存分配。

      在內存分配過程中,鎖會造成線程等待,對性能影響巨大。jemalloc采用如下措施避免線程競爭鎖的發生:使用線程變量,每個線程有自己的內存管理器,分配在這個線程內完成,就不需要和其它線程競爭鎖。

      修改方式

      步驟 1????? 下載jemalloc,參考INSTALL.md編譯安裝。

      源碼-https://github.com/jemalloc/jemalloc

      步驟 2????? 修改應用軟件的鏈接庫的方式,在編譯選項中添加如下編譯選項:

      -I`jemalloc-config --includedir`-L`jemalloc-config --libdir` -Wl,-rpath,`jemalloc-config --libdir` -ljemalloc `jemalloc-config --libs`

      具體參考 https://github.com/jemalloc/jemalloc/wiki/Getting-Started

      步驟 3????? 部分開源軟件可以修改配置參數來指定內存分配庫,如MySql可以配置my.cnf文件:malloc-lib=/usr/local/lib/libjemalloc.so

      【1024程序員節獻禮】鯤鵬性能優化十板斧(五)——應用程序性能調優

      ----結束

      1.2.7 Cacheline 優化

      原理

      CPU標識Cache中的數據是否為有效數據不是以內存位寬為單位,而是以Cacheline為單位。這個機制可能會導致偽共享(false sharing)現象,從而使得CPU的Cache命中率變低。出現偽共享的常見原因是高頻訪問的數據未按照Cacheline大小對齊:

      Cache空間大小劃分成不同的Cacheline,示意圖如下,readHighFreq雖然沒有被改寫,且在Cache中,在發生偽共享時,也是從內存中讀:

      例如以下代碼定義兩個變量,會在同一個Cacheline中,Cache會同時讀入:

      int readHighFreq, writeHighFreq

      其中readHighFreq是讀頻率高的變量,writeHighFreq為寫頻率高的變量。writeHighFreq在一個CPU core里面被改寫后,這個cache 中對應的Cacheline長度的數據被標識為無效,也就是readHighFreq被CPU core標識為無效數據,雖然readHighFreq并沒有被修改,但是CPU在訪問readHighFreq時,依然會從內存重新導入,出現偽共享導致性能降低。

      鯤鵬920和x86的Cacheline大小不一致,可能會出現在X86上優化好的程序在鯤鵬 920上運行時的性能偏低的情況,需要重新修改業務代碼數據內存對齊大小。X86 L3 cache的Cacheline大小為64字節,鯤鵬920的Cacheline為128字節。

      修改方式

      1.???????? 修改業務代碼,使得讀寫頻繁的數據以Cacheline大小對齊,修改方法可參考:

      a.???????? 使用動態申請內存的對齊方法:

      int posix_memalign(void **memptr, size_t alignment, size_t size)

      調用posix_memalign函數成功時會返回size字節的動態內存,并且這塊內存的起始地址是alignment的倍數。

      b.???????? 局部變量可以采用填充的方式:

      int writeHighFreq;

      char pad[CACHE_LINE_SIZE - sizeof(int)];

      代碼中CACHE_LINE_SIZE是服務器Cacheline的大小,pad變量沒有用處,用于填充writeHighFreq變量余下的空間,兩者之和是CacheLine大小。

      2.???????? 部分開源軟件代碼中有Cacheline的宏定義,修改宏的值即可。如在impala使用CACHE_LINE_SIZE宏來表示目標平臺的Cacheline大小。

      鯤鵬

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:要從上面弄田字格,怎么弄?(入在田字格里面怎么寫)
      下一篇:做好的文件刪了怎樣恢復(怎樣把刪除的文件恢復)
      相關文章
      亚洲精品无码久久久久久久| 亚洲精品国精品久久99热一| 久久精品国产99精品国产亚洲性色| 国产亚洲人成在线影院| 亚洲中文精品久久久久久不卡| 亚洲手机中文字幕| 亚洲精品电影在线| 亚洲特级aaaaaa毛片| 亚洲国产成a人v在线| 亚洲婷婷在线视频| 亚洲国产成人无码av在线播放| 亚洲成a人片在线观看中文app| 亚洲免费观看网站| 亚洲香蕉久久一区二区| 日韩亚洲产在线观看| 亚洲国产日韩a在线播放| 亚洲AV无码国产剧情| 日韩欧美亚洲国产精品字幕久久久| 亚洲AV成人无码久久WWW| 国产精品亚洲色婷婷99久久精品| 国产亚洲精品2021自在线| 亚洲AV无码乱码在线观看牲色| 亚洲国产精品成人网址天堂| 亚洲人成无码网站久久99热国产| 亚洲一本大道无码av天堂| 亚洲人成网亚洲欧洲无码久久| 国产AV无码专区亚洲AV毛网站| 亚洲va无码手机在线电影| 亚洲人成网站影音先锋播放| 亚洲最大在线视频| 激情综合亚洲色婷婷五月APP| 亚洲色丰满少妇高潮18p| 国产精品亚洲lv粉色| 久久亚洲中文字幕精品一区| 亚洲精品午夜无码电影网| 亚洲韩国—中文字幕| 亚洲成年人免费网站| 亚洲中文字幕无码av永久| 国产亚洲Av综合人人澡精品| 不卡一卡二卡三亚洲| 亚洲成年人在线观看|