stable_profile 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69f29fc4583e9a306a7aabbf1d9e267e924ea0be97ba6c3c592cc25899a9aa75
4
- data.tar.gz: aba44a7c4cc527a500c8e547aeda1d51944e1f2da271df0aec434967f88d6e00
3
+ metadata.gz: 924cfdff88d8cc5778394fdab96b6bf5e446d92e700e995aaddea7744fbf1eaf
4
+ data.tar.gz: d80755e9aa8810910baa570e9fca02db34efd52d3cad8bae22fb883f8c5ea2c5
5
5
  SHA512:
6
- metadata.gz: d1374fbf762bed4ec91bc9207cd225546480bf68d4b94ce978277905d18360ee992aacad83cc19a45444f39ed9481263c7a831774cccbe9ec0b21f01288c7777
7
- data.tar.gz: c761db15d550d213bc0d629874dc2f50acb693d58fba3b656eb841ae590d863f70fafb231bcbd82b37844ebf2ab5aa56a70724e3af0975a2b320b67224bb5773
6
+ metadata.gz: f1310ffc4a01c70433b737342d862e3de0540168dc43d1e237c4e0549b0376b675efb10435277ae65c15ebda335d25eaf20965b43587453ed742c6728f25959c
7
+ data.tar.gz: 9ab86cfbd9ec8194c645be23b35d94e3860da7f4a23f6967832cc82f5e84cc7dc4bb31138c4eeb05c403ee97557572b8a2b3fd38a0aaa936e9bac3daba8a82ac
@@ -4,9 +4,11 @@ require 'stable_profile'
4
4
 
5
5
  module StableProfile
6
6
  class CLI < Thor
7
- desc "profile", "Run RSpec profile with predictable results."
7
+ desc "profile", "Run RSpec profile multiple times, averaging the results."
8
+ method_option :iterations, aliases: "-i", type: :numeric, default: 20, desc: "Number of times to run RSpec"
9
+ method_option :top_slowest_examples, aliases: "-t", type: :numeric, default: 5, desc: "Number of slowest examples to output"
8
10
  def profile
9
- StableProfile.run
11
+ StableProfile.run(iterations: options[:iterations], top_slowest_examples: options[:top_slowest_examples])
10
12
  end
11
13
  default_task :profile
12
14
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'colorize'
3
4
  require 'fileutils'
4
5
  require 'json'
5
6
  require 'ruby-progressbar'
@@ -15,18 +16,8 @@ module StableProfile
15
16
  module_function
16
17
 
17
18
  # How many items to output in each category.
18
- TOP_SLOWEST_EXAMPLES = 5
19
-
20
- # The more iterations you run, the more accurate the results will be.
21
- # 20 seems like plenty, but it could take a while depending on the
22
- # size of your test suite.
23
- ITERATIONS = 4
24
-
25
- # It's a slow one if it showed up in at least half the profile runs.
26
- MINIMUM_SAMPLE_SIZE = ITERATIONS / 2
27
- DECIMAL_PLACES = 4
28
-
29
- OUTPUT_DIR = 'tmp/multi_profile'
19
+ DECIMAL_PLACES = 4
20
+ OUTPUT_DIR = 'tmp/stable_profile'
30
21
 
31
22
 
32
23
  def bold(string)
@@ -34,17 +25,17 @@ module StableProfile
34
25
  end
35
26
 
36
27
 
37
- def run
38
- puts "pwd = #{system('pwd')}"
28
+ def run(iterations:, top_slowest_examples:)
29
+ minimum_sample_size = iterations * 0.75
39
30
 
40
31
  # Erase and Create the output directory
41
32
  FileUtils.rm_rf(OUTPUT_DIR)
42
33
  FileUtils.mkdir_p(OUTPUT_DIR)
43
34
 
44
35
  # Run the specs ITERATIONS times, each time with a different random seed
45
- progressbar = ProgressBar.create(title: 'Running profiles', total: ITERATIONS, format: '%t: |%B| %p%% %a')
46
- ITERATIONS.times do |i|
47
- system("rspec --profile 50 --order random --format json > #{OUTPUT_DIR}/multi_profile_#{i+1}.json")
36
+ progressbar = ProgressBar.create(title: 'Running profiles', total: iterations, format: '%t: |%B| %p%% %a')
37
+ iterations.times do |i|
38
+ system("rspec --profile --order random --format json > #{OUTPUT_DIR}/multi_profile_#{i+1}.json")
48
39
  progressbar.increment
49
40
  end
50
41
 
@@ -82,30 +73,30 @@ module StableProfile
82
73
 
83
74
  # Mimic RSpec profile output
84
75
  puts
85
- puts "Top #{TOP_SLOWEST_EXAMPLES} slowest examples:"
76
+ puts "Top #{top_slowest_examples} slowest examples:"
86
77
  count = 0
87
78
  example_times.sort_by { |id, record| record[:average_time] }.reverse.each do |id, record|
88
79
  next if count == TOP_SLOWEST_EXAMPLES
89
- next if record[:run_times].size < MINIMUM_SAMPLE_SIZE
80
+ next if record[:run_times].size < minimum_sample_size
90
81
  count += 1
91
82
 
92
83
  example = record.fetch(:example)
93
84
 
94
- puts " #{example['full_description']}"
85
+ puts " #{example['full_description']}".colorize(:light_black)
95
86
  puts bold(" #{record[:average_time]} seconds").ljust(27) + " (N=#{record[:run_times].size})".ljust(7) + " #{example['file_path']}:#{example['line_number']}"
96
87
  end
97
88
 
98
89
  puts
99
- puts "Top #{TOP_SLOWEST_EXAMPLES} slowest example groups:"
90
+ puts "Top #{top_slowest_examples} slowest example groups:"
100
91
  count = 0
101
92
  group_times.sort_by { |id, record| record[:average_time] }.reverse.each do |id, record|
102
93
  next if count == TOP_SLOWEST_EXAMPLES
103
- next if record[:run_times].size < MINIMUM_SAMPLE_SIZE
94
+ next if record[:run_times].size < minimum_sample_size
104
95
  count += 1
105
96
 
106
97
  group = record.fetch(:group)
107
98
 
108
- puts " #{group['description']}"
99
+ puts " #{group['description']}".colorize(:light_black)
109
100
  puts bold(" #{record[:average_time]} seconds").ljust(27) + " (N=#{record[:run_times].size})".ljust(7) + " #{group['location']}"
110
101
  end
111
102
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stable_profile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robb Shecter
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-31 00:00:00.000000000 Z
11
+ date: 2023-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: ruby-progressbar
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +94,11 @@ dependencies:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: 3.12.0
83
- description: Repeatedly run --profile, averaging the results.
97
+ description: 'Solves a quirk of rspec --profile in some code bases: result vary with
98
+ every random spec ordering. This seems to be due to differences in dependency load
99
+ order, class initialization, and test server startup. This lib runs rspec --profile
100
+ many times, averaging the results to always give the same (stable) and meaningful
101
+ result.'
84
102
  email:
85
103
  - robb@public.law
86
104
  executables: