Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic support for profiling #8242

Merged
merged 1 commit into from Jul 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Expand Up @@ -65,3 +65,7 @@ TAGS

# For bundle binstubs
bin/*
!bin/rubocop-profile

# For stackprof or others
tmp/*
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@

## master (unreleased)

### New features

* [#8242](https://github.com/rubocop-hq/rubocop/pull/8242): Internal profiling available with `bin/rubocop-profile` and rake tasks. ([@marcandre][])

## 0.87.1 (2020-07-07)

### Bug fixes
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -14,6 +14,7 @@ gem 'rubocop-rspec', '~> 1.39.0'
# Stop upgrading SimpleCov until the following issue will be resolved.
# https://github.com/codeclimate/test-reporter/issues/418
gem 'simplecov', '~> 0.10', '< 0.18'
gem 'stackprof', platform: :mri
gem 'test-queue'
gem 'yard', '~> 0.9'

Expand Down
16 changes: 16 additions & 0 deletions bin/rubocop-profile
@@ -0,0 +1,16 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'stackprof'

StackProf.start
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
begin
load "#{__dir__}/../exe/rubocop"
ensure
delta = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
StackProf.stop
Dir.mkdir('tmp') unless File.exist?('tmp')
StackProf.results('tmp/stackprof.dump')
puts "Finished in #{delta.round(1)} seconds"
end
40 changes: 40 additions & 0 deletions tasks/prof.rake
@@ -0,0 +1,40 @@
# frozen_string_literal: true

namespace :prof do
DUMP_PATH = 'tmp/stackprof.dump'

desc 'Run RuboCop on itself with profiling on'
task :run, [:path] do |_task, args|
path = args.fetch(:path, '.')
cmd = "bin/rubocop-profile #{path}"
system cmd
end

task :run_if_needed, [:path] do
Rake::Task[:run].run unless File.exist?(DUMP_PATH)
end

desc 'List the slowest cops'
task slow_cops: :run_if_needed do
method = 'RuboCop::Cop::Commissioner#trigger_responding_cops'
cmd = "stackprof #{DUMP_PATH} --text --method '#{method}'"
puts cmd
output = `#{cmd}`
_header, list, _code = *output
.lines
.grep_v(/RuboCop::Cop::Commissioner/) # ignore internal calls
.slice_when { |line| line.match?(/callees.*:|code:/) }
puts list.first(40)
end

desc 'Check a particular method by walking through the callstack'
task :walk, [:method] => :run_if_needed do |_task, args|
method = args.fetch(:method) do
warn 'usage: bundle exec rake walk[Class#method]'
exit!
end
cmd = "stackprof #{DUMP_PATH} --walk --method '#{method}'"
puts cmd
system cmd
end
end