【編者按】原文做者 Emil Soman,Rubyist,除此以外居然同時也是藝術家,吉他手**,Garden City RubyConf 組織者。本文是DIY Ruby CPU Profiling 的第一部分,由 OneAPM 工程師編譯整理。**html
在 Codemancers,咱們正在建設 Rbkit——一個針對 Ruby 語言的——擁有新炫酷功能的代碼分析器。我目前正在實現一個嵌在 rbkit gem 裏的 CPU 分析器,這將有助 rbkit UI 重建分析 Ruby 進程調用圖,並在屏幕上得出有用的可視化展現。在這個過程當中,我學到了許多新東西,很樂意在本系列的博客文章中與您分享。ruby
咱們打算一步一步從基礎開始,專門爲 Ruby 編寫一個初級的 CPU 分析器!在完成時咱們將學到:服務器
什麼是 CPU 分析工具
分析模式——工具和採樣性能
CPU Time 和 Wall Time ——它們分別是什麼意思,如何測量?code
寫一個簡單的 C 擴展並用於 Ruby 中htm
Ruby Tracepoints——調用和返回進程
C 語言中的信號處理get
用一個信號暫停 Ruby 進程並用調用堆查看博客
用分析數據進行一些有用但笨拙的試驗 ###Part I. 介紹 CPU 分析 經過對你的程序進行 CPU 分析,能夠發現相較於 CPU 使用率,你的程序是多麼寶貴。爲了分析程序,你須要使用一個分析工具並按照下列步驟操做:
開始 CPU 剖析
執行你想要分析的代碼
中止 CPU 剖析並獲得剖析結果
分析結果
經過分析剖析結果,你會發現使整個程序緩慢的瓶頸。
####分析模式
CPU 剖析能夠分爲如下兩種方法:
####1. 工具 在這種模式下,分析工具利用一些 hooks,由解釋器提供或者插入程序中,來了解調用圖並測量在調用圖中每一個方法的執行時間。舉個例子,看一下下面這段 Ruby 代碼:
def main 3.times do find_many_square_roots find_many_squares end end def find_many_square_roots 5000.times{|i| Math.sqrt(i)} end def find_many_squares 5000.times{|i| i**2 } end main
我已經插入了一些內容,來幫助瞭解若是 Ruby 解釋器給了咱們方法的調用和返回的 hooks,它們如何執行:
def main # method call hook gets executed 3.times do find_many_square_roots find_many_squares end # method end hook gets executed end def find_many_square_roots # method call hook gets executed 5000.times{|i| Math.sqrt(i)} # method end hook gets executed end def find_many_squares # method call hook gets executed 5000.times{|i| i**2 } # method end hook gets executed end main
如今,若是咱們可以打印出當前時間和這些 hooks 內部當前方法的名稱,會獲得看起來像這種形式的輸出結果:
sec:00 usec:201007 called main sec:00 usec:201108 called find_many_square_roots sec:00 usec:692123 returned find_many_square_roots sec:00 usec:692178 called find_many_squares sec:00 usec:846540 returned find_many_squares sec:00 usec:846594 called find_many_square_roots sec:01 usec:336166 returned find_many_square_roots sec:01 usec:336215 called find_many_squares sec:01 usec:484880 returned find_many_squares sec:01 usec:484945 called find_many_square_roots sec:01 usec:959254 returned find_many_square_roots sec:01 usec:959315 called find_many_squares sec:02 usec:106474 returned find_many_squares sec:02 usec:106526 returned main`
正如你所看到的,此輸出能夠告訴咱們在每一種方法裏面花了多長時間。同時也告訴咱們,每個方法調用的次數。這大概就解釋了性能分析工具是如何工做的。
######優勢:
高精度 咱們獲得了方法調用數 易於實施
######缺點:
每一個被分析的方法執行 hooks 時的額外開銷
####2. 採樣
在採樣模式下,分析器每隔 x 時間單元打斷一次程序,並查看調用堆並記錄它的信息(被稱爲「樣品」)。一旦該程序完成運行,分析器收集全部樣品並找出每一個方法出如今全部樣品中的次數。 很難想象?讓咱們來看看一樣的例子代碼,看看若是咱們使用採樣分析器,輸出結果會有怎樣的不一樣。 採樣分析器的輸出結果以下:
Call stack at 0.5sec: main/find_many_square_roots Call stack at 1.0sec: main/find_many_square_roots Call stack at 1.5sec: main/find_many_square_roots Call stack at 2.0sec: main/find_many_squares`
在這個例子中,程序每 0.5 秒被中斷一次而且調用堆棧被記錄。所以,經過這個程序執行的過程咱們獲得了 4 個樣品,find_many_square_roots
記錄於 3 個樣品中, find_many_squares
只存在於一個樣品中。從本次採樣中,咱們獲得 find_many_square_roots
佔用了 75% CPU,與此同時 find_many_squares
只佔用了 25% 的 CPU 。這就大概解釋了分析器是怎麼樣工做的。
######優勢:
與工具分析相比開銷可忽略不計 很容易找到緩慢/長時間運行的方法
######缺點:
不擅長測量短期運行的方法 咱們沒有獲得方法調用數 很難本身寫出採樣分析器
####歸納
咱們只是調查了 CPU 分析的含義和兩種經常使用的 CPU 分析方法。在第 2 部分,咱們將探討對描述 CPU 使用狀況的 2 個單位進行測量—— CPU Time 和 Wall Time。咱們也會親手寫一些代碼來獲取進行測量。感謝您的閱讀!
OneAPM for Ruby 可以深刻到全部 Ruby 應用內部完成應用性能管理和監控,包括代碼級別性能問題的可見性、性能瓶頸的快速識別與追溯、真實用戶體驗監控、服務器監控和端到端的應用性能管理。 想閱讀更多技術文章,請訪問 OneAPM 官方博客。