效能工程、剖析器與看見不可見之物
原文由 Nelson Elhage 于 發布,訂閱此部落格
最近有人向我介紹了 Gary Klein 和 Robert Hoffman 合著的論文「Seeing the Invisible: Perceptual-Cognitive Aspects of Expertise」。寫得非常精彩,有機會的話我很推薦一讀。
Klein 和 Hoffman 討論了專家「看見不存在之物」的能力:除了觀察環境中實際存在的資料與線索之外,專家還能感知這些線索所隱含的意義,例如預期中卻缺席的「典型」資訊、觀察到的資料是典型還是非典型,以及根據某個時間點的快照或短暫的觀察,推斷系統過去與未來可能的时间軌跡。
我想借用這篇文章的一些觀點,放到效能工程的脈絡下談談,並聊聊剖析器能為你做什麼、又不能做什麼。特別是,我認為這篇文章提供了一個很好的視角,來說明為什麼剖析器既是不可或缺的工具,卻又遠遠不是效能工程的全部。
效能剖析器
我經常遇到——有時只是隱含地——一種迷因式的說法,認為要讓軟體跑得更快,就只有這個循環:
- 執行剖析器
- 找出剖析結果中最耗時的區段
- 把那些區段變得更快
然而實際上,無論是我自己還是他人,只要照著這個流程字面上去做,很快就會遇到報酬遞減。軟體依然比我們覺得它「應該」或「可以」達到的速度慢得多(或者就是比我們想要的慢),卻又不清楚該如何取得進一步的進展。
我認為造成這種落差的原因有很多,恐怕可以寫上十幾篇不同的文章來探討,不過就著前面那篇文章的觀點,我想先談一個想法:
剖析器只能呈現「已存在」的資訊;而高明的效能工程,則需要理解那些形塑並賦予剖析結果意義、卻「不存在」於剖析結果本身的資訊。
看見不可見之物
我這樣說是什麼意思?究竟什麼是剖析結果中「有」的資訊,什麼又是「沒有」的?
剖析器呈現的是「已存在」的東西:它非常具體、字面地告訴你,程式的某一次執行究竟把時間花在哪裡,通常是以函式或堆疊框架為單位。這當然是有用的資訊。
但這樣還不夠!有時候你會碰巧發現一個顯而易見、由明顯錯誤造成的熱點,但在更多情況下——尤其是程式已經經過某種程度的最佳化之後——你還需要額外的資訊,才能決定該採取什麼行動、嘗試哪種最佳化。光知道時間花在哪裡是不夠的;我們還得理解,哪些耗時是實際上可能消除或減少的,以及需要付出多少成本與風險。
舉個具體的例子:如果我看到程式有 80% 的時間都花在雜湊表查詢上,這代表我應該去最佳化雜湊表的實作,還是應該重新設計以減少查詢操作的次數?剖析結果本身無法直接告訴我答案,但這正是專家憑藉其專業與背景知識,仍能在剖析結果中感知到的那類資訊。
換個角度來說:剖析結果會告訴你程式在某個操作上花了多少時間;卻不會告訴你,如果你最佳化了那個操作,它又會花多少時間。
有時候,某個操作之所以慢,是因為它代表了程式的「核心工作」,是難以輕易削減的基礎工作;有時候則是出於非本質的原因才變慢,甚至有可能整個移除。剖析器會告訴你程式在這個操作上花了時間,卻不會告訴你它是否已經被妥善最佳化,或是這些工作是否可以被移除或移到別處。然而,同樣地,專家在閱讀剖析結果時,卻可能得出這些問題的答案。
甚至連剖析器所提供的分析「框架」本身,都未必是探討這些問題時最有用的框架。剖析器傾向於以時間順序及/或以函式或堆疊框架來組織資訊;但往往換一種組織方式會更有成效。例如:
有時候,以 I/O 與 CPU 時間來分析耗時更為重要;程式可能會交替執行兩者(或以不同比例平行執行),而我們想依各種 I/O 或 CPU 時間的類別來拆解耗時,這些類別未必能整齊地對應到堆疊框架上。
有時候——算是上述情況的進一步推廣——最有用的切入角度是「程式正在使用哪些硬體資源,又各佔多少比例?」視程式而定,這會開啟一整片可能的視角:
- 微架構資源:CPU 執行單元、快取空間、解碼器頻寬等
- GPU 與 CPU、PCI 或 NVLink 匯流排頻寬
- 乙太網路頻寬與本機磁碟頻寬與 CPU 吞吐量
- 以及其他許許多多面向
有時候,我們需要以不同於實體堆疊追蹤的軸線或組織框架來整理資訊。
一個典型的例子是嘗試用 C 層級的剖析器來分析 Python 程式。在這種情況下,你通常會發現大部分執行時間都花在
_PyEval_EvalFrame上。就其本身而言這並沒有錯,但也沒什麼用;你反而需要把剖析結果「提升」到 Python 層級的堆疊追蹤,才能獲得有用的理解。(這是某些「處理程式碼的程式碼」類型的自動化工具共通的問題,我過去也稍微討論過)。
與專業的交互作用
我認為 Klein 那篇關於專業的文章,為我們理解這種狀況提供了很有用的框架。
專家,尤其是特定應用領域、程式語言或框架的領域專家,往往能夠看著剖析結果就「看見」上述許多問題的答案,儘管這些答案並沒有字面地呈現在剖析結果中。
他們能夠「讀懂言外之意」,去提出甚至回答那些「正確」或「更好」的問題,而不是停留在剖析器字面上所回答的問題。更重要的是,當他們因為某些原因無法做到這一點時,專家會更快地察覺到剖析器問錯了問題,並去尋找或打造另一個工具,而不是繼續死磕同一份剖析報告,期望它 somehow 能吐出它本來就不包含的理解。
我想,這個觀點也解釋了我在相關論述與大眾對效能工程的普遍理解中所看到的一些落差。如果你觀察一位頂尖的效能工程師,的確會發現他們花很多時間在看剖析結果;由此,很容易就得出結論,認為這在某種意義上就是他們主要在做的事。
然而,若仔細觀察,這些頂尖的效能工程師使用剖析器的方式,與新手的做法、或天真旁觀者的想像截然不同。而這種用法的差異,正源於他們能在剖析結果中看見不同的資訊!當他們檢視一份剖析結果時,他們不只是看著畫面上字面顯示的資訊,而是將其作為眾多輸入之一,用來強化並建構他們對程式的模型,更新與演進他們對系統的心智模型,並據此提出與驗證假設,再透過進一步的最佳化與進一步的剖析執行(可能會換用不同的剖析器)來加以測試。
隨機一篇部落格
留言
登入後參與討論