ruby/rbs

`RBS::Prototype::Runtime#block_from_ast_of` is dominant in terms of execution time.

Opened this issue · 0 comments

ksss commented

Most of the execution time in rbs prototype runtime is taken up by RBS::Prototype::Runtime#block_from_ast_of.
This means that a significant amount of cost is being spent just to investigate whether a method's block is mandatory or not.
For example, when running rbs prototype runtime targeting ActiveSupport::*, 65% of the time is spent on this process.

The behavior of RBS::Prototype::Runtime#block_from_ast_of is not perfect, as I pointed out in #1180 (comment), and I believe a perfect judgment is fundamentally very difficult.

I feel that the use of rbs prototype runtime is being avoided due to its slow execution time.

Almost all of the execution time for RBS::Prototype::Runtime#block_from_ast_of comes from RubyVM::AbstractSyntaxTree.of, and there's no room for optimization.

I propose that rbs prototype runtime block arguments should always be considered optional.

Benchmark script

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'activesupport'
  gem 'stackprof'
end

require 'active_support/all'

ActiveSupport.eager_load!

$LOAD_PATH.unshift << File.expand_path("../lib", __dir__)
require 'rbs'

env = RBS::Environment.from_loader(RBS::EnvironmentLoader.new).resolve_type_names

StackProf.run(mode: :wall, out: "stackprof-wall.dump", interval: 100) do

RBS::Prototype::Runtime.new(
  patterns: ["ActiveSupport::*"],
  env: env,
  merge: false,
  todo: false,
  owners_included: []
).decls

end
$ bundle exec stackprof stackprof-wall.dump
==================================
  Mode: wall(100)
  Samples: 2959 (16.22% miss rate)
  GC: 519 (17.54%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      1927  (65.1%)        1925  (65.1%)     RubyVM::AbstractSyntaxTree.of
       339  (11.5%)         339  (11.5%)     (sweeping)
       266   (9.0%)         266   (9.0%)     (marking)
        33   (1.1%)          29   (1.0%)     Kernel#require
      2261  (76.4%)          24   (0.8%)     RBS::Prototype::Runtime#generate_methods
        41   (1.4%)          24   (0.8%)     Class#new
        69   (2.3%)          18   (0.6%)     RBS::Prototype::Helpers#each_node
        17   (0.6%)          17   (0.6%)     RubyVM::AbstractSyntaxTree::Node#type
        15   (0.5%)          15   (0.5%)     Module#public_instance_methods
        71   (2.4%)          15   (0.5%)     RBS::Prototype::Helpers#any_node?
        48   (1.6%)          15   (0.5%)     Module#const_get
        14   (0.5%)          14   (0.5%)     Module#private_instance_methods
        14   (0.5%)          14   (0.5%)     String#split
        14   (0.5%)          14   (0.5%)     Module#instance_method
        14   (0.5%)          14   (0.5%)     String#inspect
        13   (0.4%)          13   (0.4%)     RubyVM::AbstractSyntaxTree::Node#children
      2126  (71.8%)          12   (0.4%)     RBS::Prototype::Runtime#method_type
        32   (1.1%)          10   (0.3%)     RBS::Prototype::Runtime#each_mixined_module_one
        23   (0.8%)           9   (0.3%)     Array#inspect
        13   (0.4%)           9   (0.3%)     RBS::Prototype::Runtime#ensure_outer_module_declarations
        24   (0.8%)           8   (0.3%)     RBS::Prototype::Runtime#target_method?
        37   (1.3%)           8   (0.3%)     Array#select
        79   (2.7%)           7   (0.2%)     RBS::Prototype::Helpers#block_from_body
        28   (0.9%)           7   (0.2%)     RBS::Prototype::Runtime#const_name
         5   (0.2%)           5   (0.2%)     UnboundMethod#parameters
         5   (0.2%)           5   (0.2%)     Symbol#match?
         5   (0.2%)           4   (0.1%)     Array#sort
      2399  (81.1%)           4   (0.1%)     Array#each
        69   (2.3%)           4   (0.1%)     RBS::Prototype::Helpers#each_child
         3   (0.1%)           3   (0.1%)     Kernel#singleton_class
$ bundle exec stackprof --method RubyVM::AbstractSyntaxTree.of stackprof-wall.dump
RubyVM::AbstractSyntaxTree.of (<internal:ast>:96)
  samples:  1925 self (65.1%)  /   1927 total (65.1%)
  callers:
    1927  (  100.0%)  RBS::Prototype::Runtime#block_from_ast_of
  callees (2 total):
       2  (  100.0%)  Exception#initialize
  code:
        SOURCE UNAVAILABLE