在软件工程 中,性能分析 (performance analysis,也称为profiling),是以收集程序运行时信息为手段研究程序行为的分析方法,是一種動態程式分析 的方法。
性能分析量測像是程式的空間或時間複雜度 、特定指令的使用情形 、函式呼叫的頻率及執行時間等。性能分析的目的在于决定程序的哪个部分应该被优化 ,从而提高程序的速度或者内存使用效率。
性能分析可以由程式的源代碼 或是可執行檔進行。一般會使用稱為性能分析工具(profiler)的工具進行。性能分析工具會使用許多不同的技術,可能是以事件為基礎(Event-based)的、統計的、指令導向的、仿真的方法。性能分析工具常用在性能工程 的过程中。
性能分析工具
CodeAnalyst 性能分析工具的圖像輸出
"若要了解程式行為,程式分析工具非常重要。電腦架構分析師需要這類工具來評估程式在新的系统结构 中運作的情形。軟體撰寫者需要這類工具來分析程式,並分析出其中關鍵的區塊。編譯器 撰寫者需要這類工具來評估其指令排程 或分支預測 演算法運作的情形" -- (ATOM, PLDI, '94)
性能分析工具使用广泛的技术手段收集数据,包括硬件中断 、代码指令 、作業系统 hooking 、CPU内置的性能计数寄存器 ,等等。
性能分析输出會是:
摘要配置文件信息通常会根据事件发生的源代码语句进行注释显示,因此测量数据的大小与程序的代码大小成线性关系。
/* ------------ 源代碼------------------------- 發行次數 */
0001 IF X = "A" 0055
0002 THEN DO
0003 ADD 1 to XCOUNT 0032
0004 ELSE
0005 IF X = "B" 0055
事件的记录流则与指令路徑長度 成线性关系,也就是和运行时长成线性关系。由於資料量过大,有時记录會不切實際。所以,有些程式分析工具可以設定在某特殊條件下才啟動事件踪迹的記錄,在另外特殊條件下結束事件踪迹的記錄。
对于顺序执行的程序,通常轮廓就足够了。但并行计算 程序的性能问题(等待消息或者同步问题)和事件的時間順序有關,因此需要全部的踪迹才能找到问题。
在觀看在執行程式的相關度量時.可在任意時刻啟動或結束事件踪迹的記錄,也可以在一些關鍵的點上暫停非同步的程式來看和其他平行處理程式之間的互動關係。
历史
早在1970年代,IBM System/360 及IBM System/370 的平台就有性能分析工具,一般是用計時器中斷在固定的時間紀錄程式狀態字 (PSW)來偵測程式執行時的「過熱點」(hot spots)[来源请求 ] 。這是早期使用抽樣 方式進行性能分析的範例之一。在1974年時,指令集仿真器 就允許完整的事件踪迹,以及其他性能監控的機能。
以性能分析工具為主的UNIX程式分析至少可以回溯到1979年,當時Unix系統有一個基礎工具prof,可以列出每一個函式,也列出此函式總共花了多少時間。1982年時gprof 工具延伸此概念,可以列出完整的函式調用圖 [ 1] 。
1994年時,迪吉多 的Amitabh Srivastava和Alan Eustace提出了描述ATOM的論文[ 2] 。ATOM是一個平台,可以將程式配合其性能分析工具調整,在編譯期間 ,ATOM會在要分析的程式中加入程式碼,而加入的程式碼會輸出分析資料,這種修改程式,輸出自身分析資料的技術,稱為邏輯注入 。
2004年時,gprof和ATOM論文都出現在前50個最具影響力的程式語言設計和實現會議 (PLDI)論文中[ 3] 。
以输出方式分类
一般性能分析器
一般性能分析器(flat profiler)根據函式呼叫計算平均的函式呼叫次數,而且不會根據被呼叫函數或是執行脈絡(context)細分函式呼叫次數。
函式調用圖性能分析器
函式調用圖 性能分析器(call graph profiler)[ 4] 會顯示函數被呼叫的次數及頻率,也會列出函式調用鏈(call-chains),有些軟體會列完整的調用鏈,有些不會。
输入敏感性能分析器
输入敏感性能分析器(input-sensitive profiler)[ 5] [ 6] [ 7] 将性能度量与输入工作负载特征(例如输入大小或输入值)相关联,相比于一般性能分析器或调用图分析器增加了一个维度。它会生成图表描述应用程序性能随其输入的变化情况。
以分析方式的分類
性能分析器本身也是程式,可以在被分析程式執行時收集相關資訊,來分析該程式。根據收集到資訊的細微度,以及收集資訊的方式,可以分為事件為基礎的性能分析器,或是統計式的性能分析器。有些性能分析器為了收集資訊,會中斷程式的執行,因此在時間量測上有一定的解析度限制。
事件為基礎的性能分析器
以下列出的程式語言有事件為基礎的性能分析器:
Java :JVMTI (JVM工具介面)API ,以前稱為JVMPI(JVM性能分析介面),提供給性能分析器的hook,可以抓到像函式呼叫、類別載入、卸載、線程的進入及離開等事件。
.NET框架 :利用性能分析的API,可以連接到像是COM伺服器的性能分析代理器(profiling agent)。像Java一様,在執行會提供許多回调函式給代理器,可以捕捉到像是方法JIT /進入/離開,物件創建及其他。特別的是性能分析代理器可以用任意方式改寫目的應用程式的位元組碼。
Python :Python的性能分析包括profile模組,以調用函式圖為基礎的hotshot,以及用'sys.setprofile'函式來捕捉像c_{call,return,exception}及python_{call,return,exception}的事件。
Ruby :Ruby也用類似Python的性能分析界面。目前有在profile.rb中的一般效能分析器及相關模組。
統計式的性能分析器
有些性能分析器是用取样 的方式運作。取様式的性能分析器利用作業系統 的中斷 ,在固定時間取様目的程式的调用栈 。取様式的性能分析器在數值上較不精準,但對目的程式執行時間的影響最小,允許目的程式可以在接近全速的速度下運作。
所得到的資料不是精準值,只是統計上的近似值而已。「實際誤差的量一般會大於一個取樣時間。若某一數值是取様時間的n倍,其誤差約為n倍取样時間的平方根。」[ 8]
在實務上統計式的性能分析器會比其他的分析方式更能知道目的程式各部份占的比例,而且相較之下有較少的邊際效應 (例如記憶體快取或是指令解碼的管道線等),由於統計式的性能分析器對程式執行速度的影響較小。因此可以偵測到一些其他方式偵測不到的問題。這種方式可以看出使用者模式及可中斷系統模式(例如系統呼叫 )分別佔的時間。
不過由於系統程式需處理中斷,仍然會花一些CPU的執行周期,分散快取的讀取,而且無法分辨在不可中斷核心模式下的行為。
有些特製的硬體可以克服這類的問題:有些最近MIPS微理器中,JTAG介面有一個PCSAMPLE暫存器,可以用一種無法偵測到的方式來取様程式計數器。
最常用的統計式的性能分析器包括AMD 的CodeAnalyst 、蘋果公司 的Shark (OSX)、oprofile (Linux)[來源請求] 、Intel 的VTune 及Parallel Amplifier(Intel Parallel Studio 的一部份)。
插裝型的性能分析器
有些性能分析可以用插裝 (也稱為邏輯注入)的方式處理目的程式,也就是在目的程式中加入額外指令來收集需要的資訊。
程式的插裝會影響程式的效能,可能會出現不精確的結果及 heisenbug (捉摸不定,不易重現的bug )。插裝一定會對程式執行有些影響,常見的情形是使程式變慢。不過插裝可以特定只針對部份程式,而且可以小心控制以使影響降到最低。其對於特定程式的影響是看插裝放置的位置,以及捕捉蹤跡(trace)的機制。有些處理器有硬體支持可以捕捉蹤跡,插裝可以只佔一個机器语言 週期的時間。一般可以從結果中移除插裝的影響。
gprof是一個同時用插裝及取様的性能分析器的例子。插裝用來取得被呼叫函式的資訊,而實際花的時間則是由取様方式來獲得。
插裝是決定性能分析器可控制程度及時間解析度的關鍵。以下是一些方式的分類。
手動 :是由程式設計者加入指令,在執行時計算相關資訊,例如計算事件或是呼叫像是應用程式響應測試 (ARM)標準的API 。
源代碼層級自動處理 :依照插裝政策,利用自動化工具自動在源代碼中加入instrumentation,像Parasoft 公司的Insure++ 。
中間語言 :在組合語言 或是bytecode 中加入針對多種高階語言的instrumentation,,例如OpenPATOpenPAT 。
編譯器協助 :像gprof和Quantify都是這類的例子,像用gcc -pg ... 可以使用gprof,用quantify g++ ... 可以使用Quantify。
二進位翻譯 :此工具在編譯好的可執行檔 中加入instrumentation,例如ATOM。
執行時插裝 :代碼直接在執行前修改,工具可以完成的監控及控制程式的執行,例如用Pin 、Valgrind 、DynamoRIO 。
執行時注入 :修改程度比執行時插裝要小,代碼在執行時修改,令加入跳躍到協助用函式的指令,例如和DynInst 。
直譯器式的插裝
直譯器式除錯 選項,可以在直譯器處理每個目的指令時,收集性能量度的相關資訊。像字节码 、控制表 及JIT 的直譯器都在目的碼執行時有完整的控制能力,因此有機會收集到非常全面的資料。
hypervisor/模拟器(simulator)
相關條目
參考資料
^ gprof: a Call Graph Execution Profiler (页面存档备份 ,存于互联网档案馆 ) // Proceedings of the SIGPLAN '82 Symposium on Compiler Construction, SIGPLAN Notices, Vol. 17, No 6, pp. 120-126; doi:10.1145/800230.806987
^ Amitabh Srivastava and Alan Eustace, "Atom: A system for building customized program analysis tools", 1994 (download (页面存档备份 ,存于互联网档案馆 )) // Proceeding
PLDI '94 Proceedings of the ACM SIGPLAN 1994 conference on Programming language design and implementation. Pages 196 - 205, doi:10.1145/773473.178260
^ 20 Years of PLDI (1979–1999): A Selection, Kathryn S. McKinley, Editor . [2013-12-14 ] . (原始内容存档 于2017-10-18).
^ Graham, Susan L.; Kessler, Peter B.; Mckusick, Marshall K. Gprof: A call graph execution profiler . Proceedings of the 1982 SIGPLAN symposium on Compiler construction - SIGPLAN '82 (Boston, Massachusetts, United States: ACM Press). 1982: 120–126. ISBN 978-0-89791-074-3 . doi:10.1145/800230.806987 (英语) .
^ Coppa, Emilio; Demetrescu, Camil; Finocchi, Irene. Input-Sensitive Profiling . IEEE Transactions on Software Engineering. 2014-12-01, 40 (12): 1185–1205 [2022-02-18 ] . ISSN 0098-5589 . doi:10.1109/TSE.2014.2339825 . (原始内容 存档于2022-02-18).
^ Zaparanuks, Dmitrijs; Hauswirth, Matthias. Algorithmic profiling . Proceedings of the 33rd ACM SIGPLAN Conference on Programming Language Design and Implementation (Beijing China: ACM). 2012-06-11: 67–76 [2022-02-18 ] . ISBN 978-1-4503-1205-9 . doi:10.1145/2254064.2254074 . (原始内容 存档于2022-02-18) (英语) .
^ Lin, Hai-Xiang (编). Euro-Par 2009 – Parallel Processing Workshops: HPPC, HeteroPar, PROPER, ROIA, UNICORE, VHPC, Delft, The Netherlands, August 25-28, 2009, Revised Selected Papers. Lecture Notes in Computer Science 6043 . Berlin, Heidelberg: Springer Berlin Heidelberg https://link.springer.com/10.1007/978-3-642-14122-5 . 2010. ISBN 978-3-642-14121-8 . doi:10.1007/978-3-642-14122-5 (英语) .
^ Statistical Inaccuracy of gprof Output 互联网档案馆 的存檔 ,存档日期2012-05-29.
外部連結