##簡介html
stackprof 是基於採樣的一個調優工具,採樣有什麼好處呢?好處就是你能夠線上使用,按照內置的算法抓取一部分數據,隻影響一小部分性能。它會產生一系列的 dump 文件,而後你在線下分析這些文件,從而定位出問題,google有一篇基於採樣的論文,也基本證實了採樣是可行的。而 stackprof 也是深受 google 的 perftools 的影響,採用了採樣的方式來作調優。git
##基本使用方法github
StackProf.run(mode: :cpu, out: './stackprof.dump') do # 你的代碼 end
這裏咱們給出一段示例代碼,來做爲測試目標:算法
require "stackprof" class Compute def m1 "string" * 100 end def m2 "string" * 10000 end def start 100_000.times do m1 m2 end end end StackProf.run(mode: :cpu, out: './stackprof.dump') do Compute.new.start end
保存爲test.rb
,同時執行 ruby test.rb 就會在當前目錄下生成 stackprof.dump 文件,咱們用 stackprof 打開這個文件:ruby
stackprof stackprof.dump --text
================================== Mode: cpu(1000) Samples: 1793 (0.61% miss rate) GC: 587 (32.74%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 1106 (61.7%) 1106 (61.7%) Compute#m2 98 (5.5%) 98 (5.5%) Compute#m1 1206 (67.3%) 2 (0.1%) block in Compute#start 1206 (67.3%) 0 (0.0%) <main> 1206 (67.3%) 0 (0.0%) Compute#start 1206 (67.3%) 0 (0.0%) <main> 1206 (67.3%) 0 (0.0%) block in <main>
這裏能夠很明顯的看出是 m2 方法比較慢,佔據了大部分的執行時間,相比其餘的調優工具,它只是列出了用戶本身的方法所佔時間比,在 ruby-prof 中的測試中,它是會顯示String#*
這個方法的佔比的,可是對於咱們來講,它的意義不大,而 stackprof 是不會理會標準庫裏的方法的。同時 stackprof 也是能夠過濾方法的,好比咱們發現了 m2 這個方法有問題,那麼就能夠把它過濾出來,看看細節:工具
stackprof stackprof.dump --text --method 'Compute#m2' Compute#m2 (/Users/lizhe/Workspace/ruby-performance-tuning/test.rb:9) samples: 1106 self (61.7%) / 1106 total (61.7%) callers: 1106 ( 100.0%) block in Compute#start code: | 9 | end 1106 (61.7%) / 1106 (61.7%) | 10 | | 11 | def start
咱們能夠看到 m2 這個方法定義在哪個文件的哪一行,同時是誰調用了它,以及還顯示了它在源碼中的上下文。假若有多個方法調用了 m2 ,還會顯示出這幾個方法,以及他們調用 m2 所佔的比例,也就是上面的 callers 部分,由於只有一個 start 方法調用了 m2,因此它是 100% 。性能
##在rack中的使用方法測試
stackprof 自己實現了一個 rack middleware ,因此能夠很方便的掛載到一個 rack 應用中:ui
use StackProf::Middleware, enabled: true, mode: :cpu, save_every: 5
在 rails 中使用,先在 Gemfile 中添加 stackprof ,而後添加 middleware :google
config.middleware.use StackProf::Middleware, enabled: true, mode: :cpu, save_every: 5
而後請求你的應用,多請求幾回,每5秒鐘它會保存一次輸出結果到tmp目錄中,查看其中某一個結果:
================================== Mode: cpu(1000) Samples: 155 (0.00% miss rate) GC: 11 (7.10%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 18 (11.6%) 18 (11.6%) Hike::Index#entries 12 (7.7%) 12 (7.7%) Hike::Index#stat 9 (5.8%) 9 (5.8%) #<Module:0x007fb72a0c7b08>.load_with_autoloading 18 (11.6%) 9 (5.8%) Sprockets::Cache::FileStore#[] 6 (3.9%) 6 (3.9%) block (2 levels) in BindingOfCaller::BindingExtensions#callers 5 (3.2%) 5 (3.2%) Time.parse 5 (3.2%) 5 (3.2%) Sprockets::Mime#mime_types 5 (3.2%) 5 (3.2%) Pathname#chop_basename 4 (2.6%) 4 (2.6%) block in ActionView::PathResolver#find_template_paths 4 (2.6%) 4 (2.6%) block in BetterErrors::ExceptionExtension#set_backtrace 15 (9.7%) 3 (1.9%) block in ActiveSupport::Dependencies#load_file 2 (1.3%) 2 (1.3%) Temple::Mixins::CompiledDispatcher::DispatchNode#initialize 5 (3.2%) 2 (1.3%) ActionDispatch::Cookies::EncryptedCookieJar#initialize 2 (1.3%) 2 (1.3%) ActiveSupport::KeyGenerator#generate_key 2 (1.3%) 2 (1.3%) block in ActionView::PathResolver#query 4 (2.6%) 2 (1.3%) Slim::Parser#initialize 113 (72.9%) 2 (1.3%) ActionView::Renderer#render_template 2 (1.3%) 2 (1.3%) Hike::Trail#stat 2 (1.3%) 2 (1.3%) block in ActiveSupport::Dependencies#search_for_file 22 (14.2%) 2 (1.3%) block in Temple::Filters::MultiFlattener#on_multi 20 (12.9%) 2 (1.3%) Temple::Filters::ControlFlow#dispatcher 15 (9.7%) 2 (1.3%) ActionView::Renderer#render_partial 1 (0.6%) 1 (0.6%) block in Slim::Parser#initialize 1 (0.6%) 1 (0.6%) Pathname#prepend_prefix 1 (0.6%) 1 (0.6%) String#blank? 1 (0.6%) 1 (0.6%) ActiveSupport::SafeBuffer#initialize 10 (6.5%) 1 (0.6%) Sprockets::Asset#dependency_fresh? 1 (0.6%) 1 (0.6%) Sprockets::Asset#init_with 1 (0.6%) 1 (0.6%) Hike::Index#sort_matches 1 (0.6%) 1 (0.6%) block in ActiveSupport::Dependencies::Loadable#require
能夠利用這樣的方式調試線上的環境。
參考連接:
本文系OneAPM工程師原創文章。OneAPM是中國基礎軟件領域的新興領軍企業,能幫助企業用戶和開發者輕鬆實現:緩慢的程序代碼和SQL語句的實時抓取。想閱讀更多技術文章,請訪問OneAPM官方技術博客。