1. 程式人生 > >日誌組件優化報告

日誌組件優化報告

避免 oca 目前 nbsp \n align 4.5 獲取 成功

背景

目前項目組日誌組件存在以下問題:

1 日誌文件每寫一次日誌就打開關閉一次,存在性能浪費

2 日誌裏面獲取時間需要調用localtime、stat,在頻繁調用時該函數消耗cpu比較多

3 日誌組件獲取環境變量時未判斷是否成功,如果環境變量沒設置會引起程序core

4 日誌組件在寫日誌時,先初始化局部變量再判斷日誌級別,可以優化

5 日誌組件裏面有不少處調用了sprintf、ReplaceEnvVar和strlen,其實可以避免

6 日誌組件調用了大量不可重入函數,在信號處理函數中寫日誌可能引起core

改造方案

1 增加文件句柄緩存與輸出緩沖:

增加一個環境變量HIGH_PERFORMANCE_LOG,默認值為0,不啟用。

當HIGH_PERFORMANCE_LOG為1時,每次打開日誌後將日誌文件名記錄到g_logInfo. sFullLogName,寫完日誌後暫時不執行fclose。

下次寫日誌時判斷待寫日誌文件名是否與g_logInfo. sFullLogName一致,如果一致則不用重新打開文件。否則先將日誌文件句柄關閉再進行打開日誌文件的流程。

增加一個環境變量HIGH_PERFORMANCE_LOG_CACHE,默認值為0,不啟用。在HIGH_PERFORMANCE_LOG_CACHE和HIGH_PERFORMANCE_LOG都為1時,寫完日誌後不立即執行刷新到磁盤(不調用fflush)

2 減少非必要系統函數調用:

增加函數localtime項目組代替原來的localtime,每次調用localtime項目組時先判斷是否與上次調用間隔超過1分鐘,如果沒超過則使用上次調用localtime返回的結果,如果超過則重新調用localtime並且將結果緩存起來待下次使用。這樣從原來一分鐘調用多次localtime變成一分鐘調用一次。

修改函數CommonGetCurrentDate,首次調用時記錄當天起始秒數和第二天起始秒數,並且將返回的日誌緩存起來。之後每次調用判斷時間是否當天範圍內,如果是則直接使用緩存返回,否則重復上面流程。樣從原來天調用多次localtime變成一天調用一次。

增加環境變量LOG_SYSCALL_INTERVAL_TIMES,默認值為100,每寫LOG_SYSCALL_INTERVAL_TIMES次日誌時才執行一次stat(如果緩存打開情況,需要先調用fflush將日誌緩沖刷出),不需要每寫一次日誌就檢查一次。註意,由於每100行才檢查一次日誌大小,所以會影響原來50m切換一次日誌文件的邏輯,不一定精確的在50m時切換,會略大一些。

3 獲取環境變量失敗增加默認值:

改造原來獲取環境變量的代碼,增加環境變量獲取失敗時使用默認值的邏輯,避免異常情況下導致程序core

4 將判斷日誌級別的邏輯往前提:

進入寫日誌邏輯後,先判斷當前日誌級別是否需要輸出日誌,如果不需要則直接返回。減少非必要的變量初始化操作。

5 使用耗時較小的函數代替耗時長的函數:

日誌組件每次寫日誌時需要使用ReplaceEnvVar函數替換日誌文件路徑裏面的變量, 現改為在初始化時就調用ReplaceEnvVar將文件路徑變量替換完。後面寫日誌時使用ifNeedReplaceEnvVar判斷是否需要替換變量,如果不需要則不調用ReplaceEnvVar

把簡單的sprintf調用改為同功能其它函數代替,如將fprintf(fp, "\n")改為fputc (‘\n‘, fp)

判斷字符串是否為空,不使用strlen(str) == 0的寫法,改為str[0] == ‘\0‘

非功能測試對比

測試寫20萬行日誌改造前後日誌組件消耗時間

技術分享圖片

技術分享圖片

結果如下:

單位ms

不設置環境變量

HIGH_PERFORMANCE_LOG=1

HIGH_PERFORMANCE_LOG=1

HIGH_PERFORMANCE_LOG_CACHE=1

HIGH_PERFORMANCE_LOG=1

HIGH_PERFORMANCE_LOG_CACHE=1

LOG_SYSCALL_INTERVAL_TIMES=1000

新WrtieLog

4836.7

1001.88

453.12

454.28

新HtLog

5603.4

1355.96

1253.96

1277.58

新DebugLog

7017.66

2600.98

2323.88

2333.98

舊WrtieLog

7388.92

7442.24

7196.72

7380.76

舊HtLog

7654.6

7712.28

7498.46

7655.82

舊DebugLog

9404.58

9431.44

8805.68

9049.94

效率比

0.65

0.13

0.06

0.06

(50次平均值 測試多次結果偏差不大)

基準測試:

技術分享圖片

技術分享圖片

測試日誌記錄:

結論:

改造後日誌組件性能有所提高,效率提高約44%~70%

需要註意HIGH_PERFORMANCE_LOG環境變量啟用的情況,如果程序寫日誌過程中日誌文件被刪除或者移走,程序不能即時發現,仍然會往原來的日誌文件寫日誌。

需要等到寫滿LOG_SYSCALL_INTERVAL_TIMES行日誌後才會觸發日誌文件重新打開關閉功能。

callgrind分析情況

後續優化計劃

如果以後日誌組件再次成為性能瓶頸,可以考慮以下優化:

1 使用linux文件映射進行日誌文件讀寫,代替現有的標準庫函數。這樣可以減少數據拷貝。

2 寫日誌時使用流壓縮,邊寫日誌邊壓縮,減少磁盤消耗。

3 實在不行考慮異步落盤,先將日誌數據寫到共享內存,由專用的日誌進程寫到日誌文件。

日誌組件優化報告