mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/irb] Add measure command
You can use "measure" command to check performance in IRB like below: irb(main):001:0> 3 => 3 irb(main):002:0> measure TIME is added. => nil irb(main):003:0> 3 processing time: 0.000058s => 3 irb(main):004:0> measure :off => nil irb(main):005:0> 3 => 3 You can set "measure :on" by "IRB.conf[:MEASURE] = true" in .irbrc, and, also, set custom performance check method: IRB.conf[:MEASURE_PROC][:CUSTOM] = proc { |context, code, line_no, &block| time = Time.now result = block.() now = Time.now puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE] result } https://github.com/ruby/irb/commit/3899eaf2e2
This commit is contained in:
parent
8b6aaeaddf
commit
9f08e3c703
5 changed files with 254 additions and 1 deletions
18
lib/irb.rb
18
lib/irb.rb
|
@ -538,7 +538,23 @@ module IRB
|
||||||
signal_status(:IN_EVAL) do
|
signal_status(:IN_EVAL) do
|
||||||
begin
|
begin
|
||||||
line.untaint if RUBY_VERSION < '2.7'
|
line.untaint if RUBY_VERSION < '2.7'
|
||||||
@context.evaluate(line, line_no, exception: exc)
|
if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
|
||||||
|
IRB.set_measure_callback
|
||||||
|
end
|
||||||
|
if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
|
||||||
|
result = nil
|
||||||
|
last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) }
|
||||||
|
IRB.conf[:MEASURE_CALLBACKS].map{ |s| s.last }.inject(last_proc) { |chain, item|
|
||||||
|
proc {
|
||||||
|
item.(@context, line, line_no, exception: exc) do
|
||||||
|
chain.call
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}.call
|
||||||
|
@context.set_last_value(result)
|
||||||
|
else
|
||||||
|
@context.evaluate(line, line_no, exception: exc)
|
||||||
|
end
|
||||||
if @context.echo?
|
if @context.echo?
|
||||||
if assignment_expression?(line)
|
if assignment_expression?(line)
|
||||||
if @context.echo_on_assignment?
|
if @context.echo_on_assignment?
|
||||||
|
|
34
lib/irb/cmd/measure.rb
Normal file
34
lib/irb/cmd/measure.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require_relative "nop"
|
||||||
|
|
||||||
|
# :stopdoc:
|
||||||
|
module IRB
|
||||||
|
module ExtendCommand
|
||||||
|
class Measure < Nop
|
||||||
|
def initialize(*args)
|
||||||
|
super(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute(type = nil, arg = nil)
|
||||||
|
case type
|
||||||
|
when :off
|
||||||
|
IRB.conf[:MEASURE] = nil
|
||||||
|
IRB.unset_measure_callback(arg)
|
||||||
|
when :list
|
||||||
|
IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _|
|
||||||
|
puts "- #{type_name}"
|
||||||
|
end
|
||||||
|
when :on
|
||||||
|
IRB.conf[:MEASURE] = true
|
||||||
|
added = IRB.set_measure_callback(type)
|
||||||
|
puts "#{added.first} is added."
|
||||||
|
else
|
||||||
|
IRB.conf[:MEASURE] = true
|
||||||
|
added = IRB.set_measure_callback(type)
|
||||||
|
puts "#{added.first} is added."
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# :startdoc:
|
|
@ -125,6 +125,10 @@ module IRB # :nodoc:
|
||||||
:irb_info, :Info, "irb/cmd/info"
|
:irb_info, :Info, "irb/cmd/info"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
:measure, :Measure, "irb/cmd/measure"
|
||||||
|
],
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Installs the default irb commands:
|
# Installs the default irb commands:
|
||||||
|
|
|
@ -111,11 +111,66 @@ module IRB # :nodoc:
|
||||||
@CONF[:CONTEXT_MODE] = 4 # use a copy of TOPLEVEL_BINDING
|
@CONF[:CONTEXT_MODE] = 4 # use a copy of TOPLEVEL_BINDING
|
||||||
@CONF[:SINGLE_IRB] = false
|
@CONF[:SINGLE_IRB] = false
|
||||||
|
|
||||||
|
@CONF[:MEASURE] = false
|
||||||
|
@CONF[:MEASURE_PROC] = {}
|
||||||
|
@CONF[:MEASURE_PROC][:TIME] = proc { |context, code, line_no, &block|
|
||||||
|
time = Time.now
|
||||||
|
result = block.()
|
||||||
|
now = Time.now
|
||||||
|
puts 'processing time: %fs' % (now - time) if IRB.conf[:MEASURE]
|
||||||
|
result
|
||||||
|
}
|
||||||
|
@CONF[:MEASURE_PROC][:STACKPROF] = proc { |context, code, line_no, &block|
|
||||||
|
success = false
|
||||||
|
begin
|
||||||
|
require 'stackprof'
|
||||||
|
success = true
|
||||||
|
rescue LoadError
|
||||||
|
puts 'Please run "gem install stackprof" before measuring by StackProf.'
|
||||||
|
end
|
||||||
|
if success
|
||||||
|
result = nil
|
||||||
|
stackprof_result = StackProf.run(mode: :cpu) do
|
||||||
|
result = block.()
|
||||||
|
end
|
||||||
|
StackProf::Report.new(stackprof_result).print_text if IRB.conf[:MEASURE]
|
||||||
|
result
|
||||||
|
else
|
||||||
|
block.()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
@CONF[:MEASURE_CALLBACKS] = []
|
||||||
|
|
||||||
@CONF[:LC_MESSAGES] = Locale.new
|
@CONF[:LC_MESSAGES] = Locale.new
|
||||||
|
|
||||||
@CONF[:AT_EXIT] = []
|
@CONF[:AT_EXIT] = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def IRB.set_measure_callback(type = nil)
|
||||||
|
added = nil
|
||||||
|
if type
|
||||||
|
type_sym = type.upcase.to_sym
|
||||||
|
if IRB.conf[:MEASURE_PROC][type_sym]
|
||||||
|
added = [type_sym, IRB.conf[:MEASURE_PROC][type_sym]]
|
||||||
|
end
|
||||||
|
elsif IRB.conf[:MEASURE_PROC][:CUSTOM]
|
||||||
|
added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM]]
|
||||||
|
else
|
||||||
|
added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME]]
|
||||||
|
end
|
||||||
|
IRB.conf[:MEASURE_CALLBACKS] << added if added
|
||||||
|
added
|
||||||
|
end
|
||||||
|
|
||||||
|
def IRB.unset_measure_callback(type = nil)
|
||||||
|
if type.nil?
|
||||||
|
IRB.conf[:MEASURE_CALLBACKS].clear
|
||||||
|
else
|
||||||
|
type_sym = type.upcase.to_sym
|
||||||
|
IRB.conf[:MEASURE_CALLBACKS].reject!{ |t, c| t == type_sym }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def IRB.init_error
|
def IRB.init_error
|
||||||
@CONF[:LC_MESSAGES].load("irb/error.rb")
|
@CONF[:LC_MESSAGES].load("irb/error.rb")
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,5 +123,149 @@ module TestIRB
|
||||||
IRB.__send__(:remove_const, :IRBRC_EXT)
|
IRB.__send__(:remove_const, :IRBRC_EXT)
|
||||||
IRB.const_set(:IRBRC_EXT, ext_backup)
|
IRB.const_set(:IRBRC_EXT, ext_backup)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class TestInputMethod < ::IRB::InputMethod
|
||||||
|
attr_reader :list, :line_no
|
||||||
|
|
||||||
|
def initialize(list = [])
|
||||||
|
super("test")
|
||||||
|
@line_no = 0
|
||||||
|
@list = list
|
||||||
|
end
|
||||||
|
|
||||||
|
def gets
|
||||||
|
@list[@line_no]&.tap {@line_no += 1}
|
||||||
|
end
|
||||||
|
|
||||||
|
def eof?
|
||||||
|
@line_no >= @list.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def encoding
|
||||||
|
Encoding.default_external
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset
|
||||||
|
@line_no = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_measure
|
||||||
|
IRB.init_config(nil)
|
||||||
|
IRB.conf[:PROMPT] = {
|
||||||
|
DEFAULT: {
|
||||||
|
PROMPT_I: '> ',
|
||||||
|
PROMPT_S: '> ',
|
||||||
|
PROMPT_C: '> ',
|
||||||
|
PROMPT_N: '> '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRB.conf[:MEASURE] = false
|
||||||
|
input = TestInputMethod.new([
|
||||||
|
"3\n",
|
||||||
|
"measure\n",
|
||||||
|
"3\n",
|
||||||
|
"measure :off\n",
|
||||||
|
"3\n",
|
||||||
|
])
|
||||||
|
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
|
||||||
|
irb.context.return_format = "=> %s\n"
|
||||||
|
out, err = capture_output do
|
||||||
|
irb.eval_input
|
||||||
|
end
|
||||||
|
assert_empty err
|
||||||
|
assert_match(/\A=> 3\nTIME is added\.\n=> nil\nprocessing time: .+\n=> 3\n=> nil\n=> 3\n/, out)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_measure_enabled_by_rc
|
||||||
|
IRB.init_config(nil)
|
||||||
|
IRB.conf[:PROMPT] = {
|
||||||
|
DEFAULT: {
|
||||||
|
PROMPT_I: '> ',
|
||||||
|
PROMPT_S: '> ',
|
||||||
|
PROMPT_C: '> ',
|
||||||
|
PROMPT_N: '> '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRB.conf[:MEASURE] = true
|
||||||
|
input = TestInputMethod.new([
|
||||||
|
"3\n",
|
||||||
|
"measure :off\n",
|
||||||
|
"3\n",
|
||||||
|
])
|
||||||
|
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
|
||||||
|
irb.context.return_format = "=> %s\n"
|
||||||
|
out, err = capture_output do
|
||||||
|
irb.eval_input
|
||||||
|
end
|
||||||
|
assert_empty err
|
||||||
|
assert_match(/\Aprocessing time: .+\n=> 3\n=> nil\n=> 3\n/, out)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_measure_enabled_by_rc_with_custom
|
||||||
|
IRB.init_config(nil)
|
||||||
|
IRB.conf[:PROMPT] = {
|
||||||
|
DEFAULT: {
|
||||||
|
PROMPT_I: '> ',
|
||||||
|
PROMPT_S: '> ',
|
||||||
|
PROMPT_C: '> ',
|
||||||
|
PROMPT_N: '> '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRB.conf[:MEASURE] = true
|
||||||
|
IRB.conf[:MEASURE_PROC][:CUSTOM] = proc { |line, line_no, &block|
|
||||||
|
time = Time.now
|
||||||
|
result = block.()
|
||||||
|
now = Time.now
|
||||||
|
puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE]
|
||||||
|
result
|
||||||
|
}
|
||||||
|
input = TestInputMethod.new([
|
||||||
|
"3\n",
|
||||||
|
"measure :off\n",
|
||||||
|
"3\n",
|
||||||
|
])
|
||||||
|
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
|
||||||
|
irb.context.return_format = "=> %s\n"
|
||||||
|
out, err = capture_output do
|
||||||
|
irb.eval_input
|
||||||
|
end
|
||||||
|
assert_empty err
|
||||||
|
assert_match(/\Acustom processing time: .+\n=> 3\n=> nil\n=> 3\n/, out)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_measure_with_custom
|
||||||
|
IRB.init_config(nil)
|
||||||
|
IRB.conf[:PROMPT] = {
|
||||||
|
DEFAULT: {
|
||||||
|
PROMPT_I: '> ',
|
||||||
|
PROMPT_S: '> ',
|
||||||
|
PROMPT_C: '> ',
|
||||||
|
PROMPT_N: '> '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRB.conf[:MEASURE] = false
|
||||||
|
IRB.conf[:MEASURE_PROC][:CUSTOM] = proc { |line, line_no, &block|
|
||||||
|
time = Time.now
|
||||||
|
result = block.()
|
||||||
|
now = Time.now
|
||||||
|
puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE]
|
||||||
|
result
|
||||||
|
}
|
||||||
|
input = TestInputMethod.new([
|
||||||
|
"3\n",
|
||||||
|
"measure\n",
|
||||||
|
"3\n",
|
||||||
|
"measure :off\n",
|
||||||
|
"3\n",
|
||||||
|
])
|
||||||
|
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
|
||||||
|
irb.context.return_format = "=> %s\n"
|
||||||
|
out, err = capture_output do
|
||||||
|
irb.eval_input
|
||||||
|
end
|
||||||
|
assert_empty err
|
||||||
|
assert_match(/\A=> 3\nCUSTOM is added\.\n=> nil\ncustom processing time: .+\n=> 3\n=> nil\n=> 3\n/, out)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue