日常筆記之核心prefetch問題

2021-08-09 21:00:40 字數 2262 閱讀 1368

在缺少針對具體問題的硬資料(hard data)的時候。效能問題通常不是出在我們認為的位置,所以沒有頭緒地進行調整試圖獲得更好的效果可能是徒勞的,甚至可能使事情變得更糟糕。這是核心開 發人員得到的教訓。

在核心層面,效能通常受快取行為的影響。真正高效能要求只有命中cpu快取才能夠滿足,記憶體訪問相比較顯得過於緩慢了。核心盡量地使用cache- hot memory;以及其它一些其它重要的工作,例如調整資料結構使得經常被訪問的資料位於同一條cache line中。作為通用的準則,這些優化方法對效能的提公升很明顯。

百分百命中快取是難以達到的,但是也可以想辦法盡量提高命中率。如果核心知道最近將要訪問的資料所處的位置,它可以使用cpu提供的 prefetch 指令將資料放入快取。這種指令是通過核心prefetch()函式實現的;開發者已經在廣泛使用這個函式。例如通常使用的巨集:

#define list_for_each(pos, head) \

for (pos = (head)->next; prefetch(pos->next), pos != (head); \

pos = pos->next)

這個巨集是用於遍歷乙個鍊錶。prefetch()的思想是在處理當前實體的同時開始獲取鍊錶中下乙個實體。希望在下一次迴圈開始前能夠獲取到資料,或者至少使這個資料已經開始傳輸。眾所周知,鍊錶是對快取不友好的資料型別,所以這種型別的優化能夠有效提公升速度。

但實際上這樣做並不能提公升速度,至少在x86處理器上不能。

andi kleen可能是第乙個對這一優化方法提出疑問的,去年九月他嘗試移除list操作中的prefetch。他的patch引發了小規模的討論,但是顯然誤入了歧途。最近,linus在自己最喜歡的workloads(核心builds)之一上做了一些分析然後發現prefetch 指令集佔據了極大比例。執行prefetching所消耗的時間超出了快取帶來的好處;將prefetch()移除能夠讓made和build更快。

ingo molnar,牛人 ingo,也關注了這件事情,他進行了很有意義的研究。通過使用perf和一些細微的kernel除錯,他證明了使用prefetch()結構造成了0.5%的效能下降。這不是乙個簡單的效能退化,它本來被指望帶來更快的速度,一定有什麼地方沒有按照人們想象的方式執行。

linus指出其中最明顯的乙個問題:他的測試引入了大量對單鏈雜湊表(singly-linked hlist hash table lists)的遍歷。這些列表比較短,所有沒有足夠的範圍實現prefetching;事實上,大部分時間中,唯一的prefetch操作僅是在嘗試使用 指向列表末端的空指標。prefetching 乙個空指標看起來沒啥消耗,但實際上是有代價的: 在 x86 上(arm 也是如此)的每一條這樣的指令都會導致 a translation lookaside buffer miss and a pipeline stall. ingo 測算得出空指標的 prefetch 大約消耗 20 個 cpu 週期.

很明顯,空指標 prefetch 不是個好主意。如果cpu可以簡單的忽略對使用空指標的prefetch嘗試那麼會好一些。但是,從軟體層面解決並不是最好的辦法。ingo對只 prefetch非空指標版本的prefetch()函式進行了測試。這個版本確實效能更好。但是仍不如不使用prefetch的方案。

cpu設計者很清楚記憶體等待的代價;他們花費了大量的努力將任何可能的代價都降到最小。cpu有自己的記憶體prefetch單元,這些單元嘗試** 下一次需要的記憶體並提前對記憶體進行遍歷。ingo在他的測試中提到,即使沒有任何軟體層面的prefetch操作,cpu進行的prefetch運算元量 幾乎是相同的。所以硬體prefetcher一直處於繁忙狀態-並且在決定fetch哪些內容方面上它比軟體層面表現得更優秀。將顯式的prefetch 操作混入其中只會影響硬體的prefetch操作。

ingo總結如下:所以即便將null的部分刨除,prefetches也明顯是有害的。

他工作的成果之一:2.6.40(現在被起名叫3.0了),將prefetch()操作從鍊錶,雜湊表以及sk_buff表的遍歷操作中移除,正如 andi kleen在九月份嘗試做的那樣。或者其他的prefetch操作也被移除的話效能也有提公升的機率。核心中仍然存在prefetch()操作,不過只存在 於特定的能明確提公升效能的場景。如同我們嘗試的其他底層優化(立刻能想到的就是likely()),我們自以為prefetch能帶來幫助,但並不是我們 真正需要做的工作。

這個事情的另乙個經驗是numbers matter。andi在移除這些操作的時候是正確的,但是他不能說服社群接受自己的補丁。這一次,除了linus注意到它並進行了研究外,更重要的原因 是基於效能的補丁確實需要用資料來證明自己能夠達到設定的目標。如果andi花些時間量化他的做法帶來的影響,上一次可能就已經被大家接受了。

日常筆記之AP

ap就是傳統有線網路中的hub,也是組建小型無線區域網時最常用的裝置。ap相當於乙個連線有線網和無線網的橋梁,其主要作用是將各個無線網路客戶端連線到一起,然後將無線網路接入乙太網。大多數的無線ap都支援多使用者接入 資料加密 多速率傳送等功能,一些產品更提供了完善的無線網路管理功能。對於家庭 辦公室...

日常筆記之Buffer的拼接

nodejs中buffer模組使用頻率較高,因此在node啟動的時候自動載入。通常buffer使用的是utf8編碼方式,乙個漢字編碼是以3個utf8碼字組成,因此在讀取的時候會產生截斷,截斷的位置不是整數倍的時候會產生亂碼。常用的var fs require fs var rs fs.creater...

日常筆記之Linux的基礎

簡介 1.是乙個功能強大的作業系統 2.乙個類似unix作業系統,沒有unix就不會有linux 3.可安裝在各種計算機硬體裝置上,如手機 平板電腦 4.95 的伺服器作業系統都選擇unix linux 特點 1.開發性多使用者多工的系統 2.具有出色的穩定性和速度效能 3.具有可靠的系統安全性 4...