dev-cmd/prof: add vernier support.

It's the newest great profiler for Ruby.
This commit is contained in:
Mike McQuaid 2024-05-17 23:18:00 +09:00
parent e97864a0a8
commit fd7df63b9d
No known key found for this signature in database
6 changed files with 590 additions and 2 deletions

1
.gitignore vendored
View File

@ -138,6 +138,7 @@
**/vendor/bundle/ruby/*/gems/unicode-display_width-*/ **/vendor/bundle/ruby/*/gems/unicode-display_width-*/
**/vendor/bundle/ruby/*/gems/unparser-*/ **/vendor/bundle/ruby/*/gems/unparser-*/
**/vendor/bundle/ruby/*/gems/uri_template-*/ **/vendor/bundle/ruby/*/gems/uri_template-*/
**/vendor/bundle/ruby/*/gems/vernier-*/
**/vendor/bundle/ruby/*/gems/webrobots-*/ **/vendor/bundle/ruby/*/gems/webrobots-*/
**/vendor/bundle/ruby/*/gems/yard-*/ **/vendor/bundle/ruby/*/gems/yard-*/
**/vendor/bundle/ruby/*/gems/yard-sorbet-*/ **/vendor/bundle/ruby/*/gems/yard-sorbet-*/

View File

@ -41,6 +41,7 @@ end
group :prof, optional: true do group :prof, optional: true do
gem "ruby-prof", require: false gem "ruby-prof", require: false
gem "stackprof", require: false gem "stackprof", require: false
gem "vernier", require: false
end end
group :pry, optional: true do group :pry, optional: true do
gem "pry", require: false gem "pry", require: false

View File

@ -153,6 +153,7 @@ GEM
unf_ext unf_ext
unf_ext (0.0.9.1) unf_ext (0.0.9.1)
unicode-display_width (2.5.0) unicode-display_width (2.5.0)
vernier (1.0.1)
warning (1.3.0) warning (1.3.0)
yard (0.9.36) yard (0.9.36)
yard-sorbet (0.8.1) yard-sorbet (0.8.1)
@ -201,6 +202,7 @@ DEPENDENCIES
spoom spoom
stackprof stackprof
tapioca tapioca
vernier
warning warning
yard yard
yard-sorbet yard-sorbet

View File

@ -12,6 +12,8 @@ module Homebrew
EOS EOS
switch "--stackprof", switch "--stackprof",
description: "Use `stackprof` instead of `ruby-prof` (the default)." description: "Use `stackprof` instead of `ruby-prof` (the default)."
switch "--vernier",
description: "Use `vernier` instead of `ruby-prof` (the default)."
named_args :command, min: 1 named_args :command, min: 1
end end
@ -39,17 +41,26 @@ module Homebrew
Homebrew.setup_gem_environment! Homebrew.setup_gem_environment!
if args.stackprof? if args.stackprof?
# odeprecated. vernier is better in every way
with_env HOMEBREW_STACKPROF: "1" do with_env HOMEBREW_STACKPROF: "1" do
system(*HOMEBREW_RUBY_EXEC_ARGS, brew_rb, *args.named) system(*HOMEBREW_RUBY_EXEC_ARGS, brew_rb, *args.named)
end end
output_filename = "prof/d3-flamegraph.html" output_filename = "prof/d3-flamegraph.html"
safe_system "stackprof --d3-flamegraph prof/stackprof.dump > #{output_filename}" safe_system "stackprof --d3-flamegraph prof/stackprof.dump > #{output_filename}"
exec_browser output_filename
elsif args.vernier?
output_filename = "prof/vernier.json"
Process::UID.change_privilege(Process.euid) if Process.euid != Process.uid
safe_system "vernier", "run", "--output=#{output_filename}", "--allocation_sample_rate=500", "--",
RUBY_PATH, brew_rb, *args.named
ohai "Profiling complete!"
puts "Upload the results from #{output_filename} to:"
puts " #{Formatter.url("https://vernier.prof")}"
else else
output_filename = "prof/call_stack.html" output_filename = "prof/call_stack.html"
safe_system "ruby-prof", "--printer=call_stack", "--file=#{output_filename}", brew_rb, "--", *args.named safe_system "ruby-prof", "--printer=call_stack", "--file=#{output_filename}", brew_rb, "--", *args.named
end
exec_browser output_filename exec_browser output_filename
end
rescue OptionParser::InvalidOption => e rescue OptionParser::InvalidOption => e
ofail e ofail e

View File

@ -13,4 +13,7 @@ end
class Homebrew::DevCmd::Prof::Args < Homebrew::CLI::Args class Homebrew::DevCmd::Prof::Args < Homebrew::CLI::Args
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def stackprof?; end def stackprof?; end
sig { returns(T::Boolean) }
def vernier?; end
end end

View File

@ -0,0 +1,570 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `vernier` gem.
# Please instead update this file by running `bin/tapioca gem vernier`.
# source://vernier//lib/vernier/version.rb#3
module Vernier
class << self
# source://vernier//lib/vernier.rb#17
def profile(mode: T.unsafe(nil), **collector_options); end
# source://vernier//lib/vernier.rb#17
def run(mode: T.unsafe(nil), **collector_options); end
# source://vernier//lib/vernier.rb#38
def start_profile(mode: T.unsafe(nil), **collector_options); end
# source://vernier//lib/vernier.rb#50
def stop_profile; end
# source://vernier//lib/vernier.rb#17
def trace(mode: T.unsafe(nil), **collector_options); end
# source://vernier//lib/vernier.rb#59
def trace_retained(**profile_options, &block); end
end
end
# source://vernier//lib/vernier/collector.rb#7
class Vernier::Collector
# @return [Collector] a new instance of Collector
#
# source://vernier//lib/vernier/collector.rb#8
def initialize(mode, options = T.unsafe(nil)); end
# source://vernier//lib/vernier/collector.rb#50
def add_marker(name:, start:, finish:, thread: T.unsafe(nil), phase: T.unsafe(nil), data: T.unsafe(nil)); end
# Get the current time.
#
# This method returns the current time from Process.clock_gettime in
# integer nanoseconds. It's the same time used by Vernier internals and
# can be used to generate timestamps for custom markers.
#
# source://vernier//lib/vernier/collector.rb#46
def current_time; end
# Record an interval with a category and name. Yields to a block and
# records the amount of time spent in the block as an interval marker.
#
# source://vernier//lib/vernier/collector.rb#62
def record_interval(category, name = T.unsafe(nil)); end
def sample; end
def stack_table; end
def start; end
# source://vernier//lib/vernier/collector.rb#75
def stop; end
private
# source://vernier//lib/vernier/collector.rb#31
def add_hook(hook); end
def finish; end
def markers; end
class << self
def _new(_arg0, _arg1); end
# source://vernier//lib/vernier.rb#64
def new(mode, options = T.unsafe(nil)); end
end
end
# source://vernier//lib/vernier.rb#13
class Vernier::Error < ::StandardError; end
# source://vernier//lib/vernier/hooks.rb#4
module Vernier::Hooks; end
# source://vernier//lib/vernier/hooks/active_support.rb#5
class Vernier::Hooks::ActiveSupport
# @return [ActiveSupport] a new instance of ActiveSupport
#
# source://vernier//lib/vernier/hooks/active_support.rb#155
def initialize(collector); end
# source://vernier//lib/vernier/hooks/active_support.rb#182
def disable; end
# source://vernier//lib/vernier/hooks/active_support.rb#159
def enable; end
# source://vernier//lib/vernier/hooks/active_support.rb#187
def firefox_marker_schema; end
end
# source://vernier//lib/vernier/hooks/active_support.rb#6
Vernier::Hooks::ActiveSupport::FIREFOX_MARKER_SCHEMA = T.let(T.unsafe(nil), Array)
# source://vernier//lib/vernier/hooks/active_support.rb#148
Vernier::Hooks::ActiveSupport::SERIALIZED_KEYS = T.let(T.unsafe(nil), Hash)
# source://vernier//lib/vernier/marker.rb#6
module Vernier::Marker
class << self
# Return an array of marker names. The index of the string maps to the
# value of the corresponding constant
#
# source://vernier//lib/vernier/marker.rb#34
def name_table; end
end
end
# source://vernier//lib/vernier/marker.rb#13
Vernier::Marker::MARKER_STRINGS = T.let(T.unsafe(nil), Array)
# source://vernier//lib/vernier/marker.rb#7
Vernier::Marker::MARKER_SYMBOLS = T.let(T.unsafe(nil), Array)
module Vernier::Marker::Phase; end
Vernier::Marker::Phase::INSTANT = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Phase::INTERVAL = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Phase::INTERVAL_END = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Phase::INTERVAL_START = T.let(T.unsafe(nil), Integer)
module Vernier::Marker::Type; end
Vernier::Marker::Type::GC_END_MARK = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GC_END_SWEEP = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GC_ENTER = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GC_EXIT = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GC_PAUSE = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GC_START = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GVL_THREAD_EXITED = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::GVL_THREAD_STARTED = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::THREAD_RUNNING = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::THREAD_STALLED = T.let(T.unsafe(nil), Integer)
Vernier::Marker::Type::THREAD_SUSPENDED = T.let(T.unsafe(nil), Integer)
# source://vernier//lib/vernier/middleware.rb#2
class Vernier::Middleware
# @return [Middleware] a new instance of Middleware
#
# source://vernier//lib/vernier/middleware.rb#3
def initialize(app, permit: T.unsafe(nil)); end
# source://vernier//lib/vernier/middleware.rb#8
def call(env); end
end
# source://vernier//lib/vernier/output/firefox.rb#7
module Vernier::Output; end
# https://profiler.firefox.com/
# https://github.com/firefox-devtools/profiler/blob/main/src/types/profile.js
#
# source://vernier//lib/vernier/output/firefox.rb#10
class Vernier::Output::Firefox
# @return [Firefox] a new instance of Firefox
#
# source://vernier//lib/vernier/output/firefox.rb#88
def initialize(profile); end
# source://vernier//lib/vernier/output/firefox.rb#93
def output(gzip: T.unsafe(nil)); end
private
# source://vernier//lib/vernier/output/firefox.rb#106
def data; end
# source://vernier//lib/vernier/output/firefox.rb#151
def marker_schema; end
# Returns the value of attribute profile.
#
# source://vernier//lib/vernier/output/firefox.rb#104
def profile; end
end
# source://vernier//lib/vernier/output/firefox.rb#11
class Vernier::Output::Firefox::Categorizer
# @return [Categorizer] a new instance of Categorizer
#
# source://vernier//lib/vernier/output/firefox.rb#13
def initialize; end
# @yield [category]
#
# source://vernier//lib/vernier/output/firefox.rb#43
def add_category(name:, **kw); end
# Returns the value of attribute categories.
#
# source://vernier//lib/vernier/output/firefox.rb#12
def categories; end
# source://vernier//lib/vernier/output/firefox.rb#64
def categorize(path); end
# source://vernier//lib/vernier/output/firefox.rb#60
def gem_path(*names); end
# source://vernier//lib/vernier/output/firefox.rb#52
def get_category(name); end
# source://vernier//lib/vernier/output/firefox.rb#56
def starts_with(*paths); end
end
# source://vernier//lib/vernier/output/firefox.rb#68
class Vernier::Output::Firefox::Categorizer::Category
# @return [Category] a new instance of Category
#
# source://vernier//lib/vernier/output/firefox.rb#70
def initialize(idx, name:, color:, matcher: T.unsafe(nil)); end
# source://vernier//lib/vernier/output/firefox.rb#78
def add_subcategory(**args); end
# Returns the value of attribute color.
#
# source://vernier//lib/vernier/output/firefox.rb#69
def color; end
# Returns the value of attribute idx.
#
# source://vernier//lib/vernier/output/firefox.rb#69
def idx; end
# Returns the value of attribute matcher.
#
# source://vernier//lib/vernier/output/firefox.rb#69
def matcher; end
# @return [Boolean]
#
# source://vernier//lib/vernier/output/firefox.rb#82
def matches?(path); end
# Returns the value of attribute name.
#
# source://vernier//lib/vernier/output/firefox.rb#69
def name; end
# Returns the value of attribute subcategories.
#
# source://vernier//lib/vernier/output/firefox.rb#69
def subcategories; end
end
# source://vernier//lib/vernier/output/firefox.rb#206
class Vernier::Output::Firefox::Thread
# @return [Thread] a new instance of Thread
#
# source://vernier//lib/vernier/output/firefox.rb#209
def initialize(ruby_thread_id, profile, categorizer, name:, tid:, samples:, weights:, markers:, started_at:, timestamps: T.unsafe(nil), sample_categories: T.unsafe(nil), stopped_at: T.unsafe(nil), allocations: T.unsafe(nil), is_main: T.unsafe(nil)); end
# source://vernier//lib/vernier/output/firefox.rb#373
def allocations_table; end
# source://vernier//lib/vernier/output/firefox.rb#301
def data; end
# source://vernier//lib/vernier/output/firefox.rb#280
def filter_filenames(filenames); end
# source://vernier//lib/vernier/output/firefox.rb#454
def frame_table; end
# source://vernier//lib/vernier/output/firefox.rb#478
def func_table; end
# source://vernier//lib/vernier/output/firefox.rb#333
def markers_table; end
# Returns the value of attribute profile.
#
# source://vernier//lib/vernier/output/firefox.rb#207
def profile; end
# source://vernier//lib/vernier/output/firefox.rb#392
def samples_table; end
# source://vernier//lib/vernier/output/firefox.rb#429
def stack_table; end
# source://vernier//lib/vernier/output/firefox.rb#503
def string_table; end
private
# source://vernier//lib/vernier/output/firefox.rb#509
def gc_category; end
# source://vernier//lib/vernier/output/firefox.rb#513
def thread_category; end
end
# source://vernier//lib/vernier/output/top.rb#5
class Vernier::Output::Top
# @return [Top] a new instance of Top
#
# source://vernier//lib/vernier/output/top.rb#6
def initialize(profile); end
# source://vernier//lib/vernier/output/top.rb#10
def output; end
end
# source://vernier//lib/vernier/result.rb#2
class Vernier::Result
# source://vernier//lib/vernier/result.rb#57
def each_sample; end
# source://vernier//lib/vernier/result.rb#49
def elapsed_seconds; end
# Returns the value of attribute end_time.
#
# source://vernier//lib/vernier/result.rb#19
def end_time; end
# Sets the attribute end_time
#
# @param value the value to set the attribute end_time to.
#
# source://vernier//lib/vernier/result.rb#19
def end_time=(_arg0); end
# source://vernier//lib/vernier/result.rb#7
def frame_table; end
# source://vernier//lib/vernier/result.rb#11
def func_table; end
# Returns the value of attribute hooks.
#
# source://vernier//lib/vernier/result.rb#17
def hooks; end
# Sets the attribute hooks
#
# @param value the value to set the attribute hooks to.
#
# source://vernier//lib/vernier/result.rb#17
def hooks=(_arg0); end
# source://vernier//lib/vernier/result.rb#53
def inspect; end
# source://vernier//lib/vernier/result.rb#23
def main_thread; end
# Returns the value of attribute markers.
#
# source://vernier//lib/vernier/result.rb#15
def markers; end
# Returns the value of attribute meta.
#
# source://vernier//lib/vernier/result.rb#21
def meta; end
# Sets the attribute meta
#
# @param value the value to set the attribute meta to.
#
# source://vernier//lib/vernier/result.rb#21
def meta=(_arg0); end
# Returns the value of attribute pid.
#
# source://vernier//lib/vernier/result.rb#19
def pid; end
# Sets the attribute pid
#
# @param value the value to set the attribute pid to.
#
# source://vernier//lib/vernier/result.rb#19
def pid=(_arg0); end
# source://vernier//lib/vernier/result.rb#30
def sample_categories; end
# source://vernier//lib/vernier/result.rb#29
def samples; end
# source://vernier//lib/vernier/result.rb#149
def stack(idx); end
# source://vernier//lib/vernier/result.rb#3
def stack_table; end
# Realtime in nanoseconds since the unix epoch
#
# source://vernier//lib/vernier/result.rb#33
def started_at; end
# Returns the value of attribute threads.
#
# source://vernier//lib/vernier/result.rb#20
def threads; end
# Sets the attribute threads
#
# @param value the value to set the attribute threads to.
#
# source://vernier//lib/vernier/result.rb#20
def threads=(_arg0); end
# source://vernier//lib/vernier/result.rb#40
def to_gecko(gzip: T.unsafe(nil)); end
# source://vernier//lib/vernier/result.rb#153
def total_bytes; end
# TODO: remove these
#
# source://vernier//lib/vernier/result.rb#28
def weights; end
# source://vernier//lib/vernier/result.rb#44
def write(out:); end
end
# source://vernier//lib/vernier/result.rb#66
class Vernier::Result::BaseType
# @return [BaseType] a new instance of BaseType
#
# source://vernier//lib/vernier/result.rb#68
def initialize(result, idx); end
# Returns the value of attribute idx.
#
# source://vernier//lib/vernier/result.rb#67
def idx; end
# source://vernier//lib/vernier/result.rb#77
def inspect; end
# Returns the value of attribute result.
#
# source://vernier//lib/vernier/result.rb#67
def result; end
# source://vernier//lib/vernier/result.rb#73
def to_s; end
end
# source://vernier//lib/vernier/result.rb#97
class Vernier::Result::Frame < ::Vernier::Result::BaseType
# source://vernier//lib/vernier/result.rb#99
def filename; end
# source://vernier//lib/vernier/result.rb#102
def func; end
# source://vernier//lib/vernier/result.rb#98
def label; end
# source://vernier//lib/vernier/result.rb#107
def line; end
# source://vernier//lib/vernier/result.rb#98
def name; end
# source://vernier//lib/vernier/result.rb#111
def to_s; end
end
# source://vernier//lib/vernier/result.rb#82
class Vernier::Result::Func < ::Vernier::Result::BaseType
# source://vernier//lib/vernier/result.rb#88
def filename; end
# source://vernier//lib/vernier/result.rb#83
def label; end
# source://vernier//lib/vernier/result.rb#83
def name; end
# source://vernier//lib/vernier/result.rb#92
def to_s; end
end
# source://vernier//lib/vernier/result.rb#116
class Vernier::Result::Stack < ::Vernier::Result::BaseType
# source://vernier//lib/vernier/result.rb#117
def each_frame; end
# source://vernier//lib/vernier/result.rb#136
def frames; end
# source://vernier//lib/vernier/result.rb#132
def leaf_frame; end
# source://vernier//lib/vernier/result.rb#128
def leaf_frame_idx; end
# source://vernier//lib/vernier/result.rb#140
def to_s; end
end
# source://vernier//lib/vernier/stack_table.rb#2
class Vernier::StackTable
# source://vernier//lib/vernier/stack_table.rb#25
def backtrace(stack_idx); end
def current_stack(*_arg0); end
def frame_count; end
def frame_func_idx(_arg0); end
def frame_line_no(_arg0); end
# source://vernier//lib/vernier/stack_table.rb#37
def full_stack(stack_idx); end
def func_count; end
def func_filename(_arg0); end
def func_first_lineno(_arg0); end
def func_name(_arg0); end
# source://vernier//lib/vernier/stack_table.rb#3
def inspect; end
def stack_count; end
def stack_frame_idx(_arg0); end
def stack_parent_idx(_arg0); end
# source://vernier//lib/vernier/stack_table.rb#7
def to_h; end
class << self
def new; end
end
end
# Collects names of all seen threads
#
# source://vernier//lib/vernier/thread_names.rb#3
class Vernier::ThreadNames
# @return [ThreadNames] a new instance of ThreadNames
#
# source://vernier//lib/vernier/thread_names.rb#4
def initialize; end
# source://vernier//lib/vernier/thread_names.rb#12
def [](object_id); end
# source://vernier//lib/vernier/thread_names.rb#16
def finish; end
private
# source://vernier//lib/vernier/thread_names.rb#23
def collect_running; end
# source://vernier//lib/vernier/thread_names.rb#29
def collect_thread(th); end
# source://vernier//lib/vernier/thread_names.rb#33
def pretty_name(thread); end
end
# source://vernier//lib/vernier/version.rb#4
Vernier::VERSION = T.let(T.unsafe(nil), String)