derailed_benchmarks 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 534c94c162b5f9959a2013292d3f58fdf3bad5f17276a6db240a75596f1b041e
4
- data.tar.gz: e7db4cf3bb3ea0f965dd25af1dcfe1a85dbfb80d6c3508e295ac68432b4e9868
3
+ metadata.gz: 843a6c3b99ee45120c15af62a592e9bbecb2d88f0917fa292faf9f7128ab721a
4
+ data.tar.gz: f1cdfb9c4145c27a8dac7f2c868077c6359213c3c367f2cf8a0f8909f50c9468
5
5
  SHA512:
6
- metadata.gz: 4f39f3b7df3d063c703df439aba0dd0be34650bbbf490d9af11c28dac0a9449eb347bfd9201124bedfea3b53b6f731280fafa5a9f6e40e7c311d1584b5061e13
7
- data.tar.gz: 151966ff16e1e07bf217ce88e3c4868089eb2ef6428ddd6e93d8d3761d97902a4c4ee8cca32389e80e5dcaf658f21c121e9a9bffcd2a52d80985e1560021767d
6
+ metadata.gz: 1936293cd836af98e6af454a7482534c7481b938f4944813a5261a04a9b766b0a169b866397b3d9745d25316cd8916df3b74fc1fd4f1ff46f6e5753eba92bd96
7
+ data.tar.gz: 7de041007e174314699cac83eef5b70626e5447eddd705190d68d74cc7d50c0b9d660d032127cf747ea67566a096bbca4aafa05774c413da6f4ca802c8da2c08
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## 1.7.0
4
+
5
+ - Add histogram support to `perf:library` (https://github.com/schneems/derailed_benchmarks/pull/169)
6
+ - Fix bug with `Kernel#require` patch when Zeitwerk is enabled (https://github.com/schneems/derailed_benchmarks/pull/170)
7
+
3
8
  ## 1.6.0
4
9
 
5
10
  - Added the `perf:app` command to compare commits within the same application. (https://github.com/schneems/derailed_benchmarks/pull/157)
@@ -30,6 +30,8 @@ Gem::Specification.new do |gem|
30
30
  gem.add_dependency "rake", "> 10", "< 14"
31
31
  gem.add_dependency "thor", ">= 0.19", "< 2"
32
32
  gem.add_dependency "ruby-statistics", ">= 2.1"
33
+ gem.add_dependency "unicode_plot", ">= 0.0.4", "< 1.0.0"
34
+ gem.add_dependency "mini_histogram", "~> 0"
33
35
 
34
36
  gem.add_development_dependency "capybara", "~> 2"
35
37
  gem.add_development_dependency "m"
@@ -11,14 +11,20 @@ ENV['CUT_OFF'] ||= "0.3"
11
11
  # Monkey patch kernel to ensure that all `require` calls call the same
12
12
  # method
13
13
  module Kernel
14
+ REQUIRE_STACK = []
14
15
 
15
- private
16
+ module_function
16
17
 
17
- alias :original_require :require
18
- REQUIRE_STACK = []
18
+ alias_method :original_require, :require
19
+ alias_method :original_require_relative, :require_relative
19
20
 
20
21
  def require(file)
21
- Kernel.require(file)
22
+ measure_memory_impact(file) do |file|
23
+ # "source_annotation_extractor" is deprecated in Rails 6
24
+ # # if we don't skip the library it leads to a crash
25
+ # next if file == "rails/source_annotation_extractor" && Rails.version >= '6.0'
26
+ original_require(file)
27
+ end
22
28
  end
23
29
 
24
30
  def require_relative(file)
@@ -29,10 +35,7 @@ module Kernel
29
35
  end
30
36
  end
31
37
 
32
- class << self
33
- alias :original_require :require
34
- alias :original_require_relative :require_relative
35
- end
38
+ private
36
39
 
37
40
  # The core extension we use to measure require time of all requires
38
41
  # When a file is required we create a tree node with its file name.
@@ -46,7 +49,7 @@ module Kernel
46
49
  # When a require returns we remove it from the require stack so we don't
47
50
  # accidentally push additional children nodes to it. We then store the
48
51
  # memory cost of the require in the tree node.
49
- def self.measure_memory_impact(file, &block)
52
+ def measure_memory_impact(file, &block)
50
53
  mem = GetProcessMem.new
51
54
  node = DerailedBenchmarks::RequireTree.new(file)
52
55
 
@@ -68,15 +71,6 @@ end
68
71
  TOP_REQUIRE = DerailedBenchmarks::RequireTree.new("TOP")
69
72
  REQUIRE_STACK.push(TOP_REQUIRE)
70
73
 
71
- Kernel.define_singleton_method(:require) do |file|
72
- measure_memory_impact(file) do |file|
73
- # "source_annotation_extractor" is deprecated in Rails 6
74
- # # if we don't skip the library it leads to a crash
75
- # next if file == "rails/source_annotation_extractor" && Rails.version >= '6.0'
76
- original_require(file)
77
- end
78
- end
79
-
80
74
  class Object
81
75
  private
82
76
 
@@ -30,7 +30,7 @@ namespace :perf do
30
30
  DERAILED_APP.initialize! unless DERAILED_APP.instance_variable_get(:@initialized)
31
31
  end
32
32
 
33
- if ENV["DERAILED_SKIP_ACTIVE_RECORD"] && defined? ActiveRecord
33
+ if !ENV["DERAILED_SKIP_ACTIVE_RECORD"] && defined? ActiveRecord
34
34
  if defined? ActiveRecord::Tasks::DatabaseTasks
35
35
  ActiveRecord::Tasks::DatabaseTasks.create_current
36
36
  else # Rails 3.2
@@ -39,7 +39,14 @@ namespace :perf do
39
39
 
40
40
  ActiveRecord::Migrator.migrations_paths = DERAILED_APP.paths['db/migrate'].to_a
41
41
  ActiveRecord::Migration.verbose = true
42
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, nil)
42
+
43
+ if Rails.version.start_with? '6'
44
+ ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration).migrate
45
+ elsif Rails.version.start_with? '5.2'
46
+ ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths).migrate
47
+ else
48
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, nil)
49
+ end
43
50
  end
44
51
 
45
52
  DERAILED_APP.config.consider_all_requests_local = true
@@ -135,4 +142,4 @@ namespace :perf do
135
142
  WARM_COUNT.times { call_app }
136
143
  end
137
144
  end
138
- end
145
+ end
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'bigdecimal'
4
4
  require 'statistics'
5
+ require 'unicode_plot'
6
+ require 'stringio'
7
+ require 'mini_histogram'
5
8
 
6
9
  module DerailedBenchmarks
7
10
  # A class used to read several benchmark files
@@ -100,7 +103,26 @@ module DerailedBenchmarks
100
103
  " " * (percent_faster.to_s.index(".") - x_faster.to_s.index("."))
101
104
  end
102
105
 
103
- def banner(io = Kernel)
106
+ def histogram(io = $stdout)
107
+ newest_histogram = MiniHistogram.new(newest.values)
108
+ oldest_histogram = MiniHistogram.new(oldest.values)
109
+ MiniHistogram.set_average_edges!(newest_histogram, oldest_histogram)
110
+
111
+ {newest => newest_histogram, oldest => oldest_histogram}.each do |report, histogram|
112
+ plot = UnicodePlot.histogram(
113
+ histogram,
114
+ title: "\n#{' ' * 18 }Histogram - [#{report.name}] #{report.desc.inspect}",
115
+ ylabel: "Time (s)",
116
+ xlabel: "# of runs in range"
117
+ )
118
+ plot.render(io)
119
+ io.puts
120
+ end
121
+
122
+ io.puts
123
+ end
124
+
125
+ def banner(io = $stdout)
104
126
  io.puts
105
127
  if significant?
106
128
  io.puts "❤️ ❤️ ❤️ (Statistically Significant) ❤️ ❤️ ❤️"
@@ -122,6 +144,9 @@ module DerailedBenchmarks
122
144
  io.puts "Is significant? (max > critical): #{significant?}"
123
145
  io.puts "D critical: #{d_critical}"
124
146
  io.puts "D max: #{d_max}"
147
+
148
+ histogram(io)
149
+
125
150
  io.puts
126
151
  end
127
152
  end
@@ -88,7 +88,8 @@ namespace :perf do
88
88
 
89
89
  if (i % 50).zero?
90
90
  puts "Intermediate result"
91
- stats.call.banner
91
+ stats.call
92
+ stats.banner
92
93
  puts "Continuing execution"
93
94
  end
94
95
  end
@@ -102,7 +103,8 @@ namespace :perf do
102
103
  end
103
104
 
104
105
  if stats
105
- stats.call.banner
106
+ stats.call
107
+ stats.banner
106
108
 
107
109
  result_file = out_dir + "results.txt"
108
110
  File.open(result_file, "w") do |f|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DerailedBenchmarks
4
- VERSION = "1.6.0"
4
+ VERSION = "1.7.0"
5
5
  end
@@ -29,6 +29,22 @@ class StatsFromDirTest < ActiveSupport::TestCase
29
29
  assert_equal "11.3844", format % newest.median
30
30
  end
31
31
 
32
+ test "histogram output" do
33
+ dir = fixtures_dir("stats/significant")
34
+ branch_info = {}
35
+ branch_info["loser"] = { desc: "Old commit", time: Time.now, file: dir.join("loser.bench.txt"), name: "loser" }
36
+ branch_info["winner"] = { desc: "I am the new commit", time: Time.now + 1, file: dir.join("winner.bench.txt"), name: "winner" }
37
+ stats = DerailedBenchmarks::StatsFromDir.new(branch_info).call
38
+
39
+ io = StringIO.new
40
+ stats.call.banner(io)
41
+ puts io.string
42
+
43
+ assert_match(/11\.2 , 11\.28/, io.string)
44
+ assert_match(/11\.8 , 11\.88/, io.string)
45
+ end
46
+
47
+
32
48
  test "alignment" do
33
49
  dir = fixtures_dir("stats/significant")
34
50
  branch_info = {}
@@ -26,7 +26,7 @@ class TasksTest < ActiveSupport::TestCase
26
26
  env_string = env.map {|key, value| "#{key.shellescape}=#{value.to_s.shellescape}" }.join(" ")
27
27
  cmd = "env #{env_string} bundle exec rake -f perf.rake #{cmd} --trace"
28
28
  puts "Running: #{cmd}"
29
- result = `cd '#{rails_app_path}' && #{cmd}`
29
+ result = Bundler.with_original_env { `cd '#{rails_app_path}' && #{cmd}` }
30
30
  if assert_success
31
31
  assert $?.success?, "Expected '#{cmd}' to return a success status.\nOutput: #{result}"
32
32
  end
@@ -13,6 +13,8 @@ require 'devise'
13
13
 
14
14
  module Dummy
15
15
  class Application < Rails::Application
16
+ config.load_defaults Rails.version.to_f
17
+
16
18
  config.action_mailer.default_url_options = { host: 'localhost:3000' }
17
19
 
18
20
  # Settings in config/environments/* take precedence over those specified here.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: derailed_benchmarks
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Schneeman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-14 00:00:00.000000000 Z
11
+ date: 2020-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: heapy
@@ -134,6 +134,40 @@ dependencies:
134
134
  - - ">="
135
135
  - !ruby/object:Gem::Version
136
136
  version: '2.1'
137
+ - !ruby/object:Gem::Dependency
138
+ name: unicode_plot
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: 0.0.4
144
+ - - "<"
145
+ - !ruby/object:Gem::Version
146
+ version: 1.0.0
147
+ type: :runtime
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: 0.0.4
154
+ - - "<"
155
+ - !ruby/object:Gem::Version
156
+ version: 1.0.0
157
+ - !ruby/object:Gem::Dependency
158
+ name: mini_histogram
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ type: :runtime
165
+ prerelease: false
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
137
171
  - !ruby/object:Gem::Dependency
138
172
  name: capybara
139
173
  requirement: !ruby/object:Gem::Requirement