為了調試一個功能,在一個內核模塊中,增加了一個全局變量,用來統計自有skb池的申請情況。
因為是臨時增加,所以沒有考慮性能,一開始只是一個fail的統計,數量不多,也不太考慮是否有計數丟失的情況,畢竟那個賣火車票的例子已經讓很多人知道了並發導致的計數丟失。
因為只是一個簡單統計,這樣做無可厚非。
后來有人維護的時候,增加了一個success的統計,結果發現增加該變量前后cpu占用增加了一個點。為了排除是偽共享的行為,我將兩個變量中間增加了一些reserve的空間,結果還是如此。去掉success統計,立刻恢復。一個簡單的計數居然導致如此的性能變化,只能祭出倚天劍了,perf上馬。
根據perf stat 的統計,我發現 cache-misses這一行有明顯的增長,
最后排查的原因就是,由於是一個多核的設備,每個cpu都會對這個變量進行++,也就是這個變量是一個熱點,當A cpu對其++的時候,根據mesi協議,顯然會發送讓其他cpu對這個變量進行讀緩存失效,並且還需要等待其他cpu的回復的最新的緩存值。雖然這個過程是由硬件實現的,但對性能的影響卻是顯而易見的。
所以將這個統計改成percpu變量,然后需要show的時候,將各個cpu相加起來就ok。犧牲了部分准確性,但提高了性能,因為性能這個詞,本來就是一種權衡,不管是用時間換空間還是空間換時間。
所以多核並發,針對統計類的實現,最好實現成percpu的。這個就是經典的並行拆分思路。
ps:
推薦對並發編程感興趣的童鞋,可以參考老謝和魯陽翻譯的《深入理解並行編程》。