gem_footprint_analyzer 0.1.5 → 0.1.6

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: 8e977cf9fc36c1045294e18296c00c63ab7b7e1ccf482691cb85a231a4e18273
4
- data.tar.gz: d917cd40bb4ca7d2f608928337a880a04ef7bdb71a352fccb7279e46ca40d42b
3
+ metadata.gz: 4ea3f3ac4a4cdc86a560ae500fdbdc59423afe2d28ac9f16f5fdc7efe5d433fc
4
+ data.tar.gz: 5baf82c20f15679d84b56f86e303e81325aadbc4577fdcc6bc36a388d0b92baa
5
5
  SHA512:
6
- metadata.gz: c6c448e829e042a6620f774102cb04a80eca75fd9bc4c3b1593ffcd6b4947088493d51e789f90a298176c3f7c849c924f40f923cd5c923e18aa70b2a7e977fac
7
- data.tar.gz: f16657789a803c5ee278e6af25e5b8505d2c97ebae833ee2b3f5fb13a69febe5b94509459cd6452e6e4cf6192c98ec743c672c20228db80fa5c61cd8d5b7e0b9
6
+ metadata.gz: 54b934c3cb13d9b564f52abc70adc1286c5842acb2e0c25d178131d6d1e653732f9a1d49df807004fc434089e97f119fbf32ddee75af29e488e1df415b58bbfe
7
+ data.tar.gz: 50bb084a66ae63808ee91acde1c257cda615cb28cb2ea2ee71463306e7d8ca2b59a3fcf1e4d09d2fe3ebef8e1c6fb12e4440b4a5c3f523a6108b03bf4d44fbdc
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gem_footprint_analyzer (0.1.5)
4
+ gem_footprint_analyzer (0.1.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -10,7 +10,7 @@ GEM
10
10
  diff-lcs (1.3)
11
11
  jaro_winkler (1.5.1)
12
12
  parallel (1.12.1)
13
- parser (2.5.1.2)
13
+ parser (2.5.3.0)
14
14
  ast (~> 2.4.0)
15
15
  powerpack (0.1.2)
16
16
  rainbow (3.0.0)
@@ -36,8 +36,8 @@ GEM
36
36
  rainbow (>= 2.2.2, < 4.0)
37
37
  ruby-progressbar (~> 1.7)
38
38
  unicode-display_width (~> 1.4.0)
39
- rubocop-rspec (1.30.0)
40
- rubocop (>= 0.58.0)
39
+ rubocop-rspec (1.30.1)
40
+ rubocop (>= 0.60.0)
41
41
  ruby-progressbar (1.10.0)
42
42
  unicode-display_width (1.4.0)
43
43
 
@@ -50,7 +50,7 @@ DEPENDENCIES
50
50
  rake (~> 10.0)
51
51
  rspec (~> 3.0)
52
52
  rubocop (~> 0.60.0)
53
- rubocop-rspec
53
+ rubocop-rspec (~> 1.30)
54
54
 
55
55
  BUNDLED WITH
56
56
  1.17.1
data/README.md CHANGED
@@ -10,7 +10,7 @@ Requires Ruby >= 2.2.0, works on Linux and MacOS.
10
10
  Add this line to your application's Gemfile:
11
11
 
12
12
  ```ruby
13
- gem 'gem_footprint_analyzer'
13
+ gem 'gem_footprint_analyzer', require: false
14
14
  ```
15
15
 
16
16
  And then execute:
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby --disable=did_you_mean --disable=gem --disable=rubyopt
1
+ #!/usr/bin/env ruby --disable=gem --disable=rubyopt
2
2
 
3
3
  $LOAD_PATH.unshift(File.join(__dir__, '..', 'lib'))
4
4
  $LOAD_PATH.unshift('./lib') if Dir.exist?('lib')
@@ -7,7 +7,7 @@ require 'gem_footprint_analyzer'
7
7
 
8
8
  cli = GemFootprintAnalyzer::CLI.new
9
9
 
10
- t1 = Time.now.to_f
10
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
11
11
  cli.run(ARGV)
12
- t2 = Time.now.to_f
12
+ t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
13
13
  STDERR.puts(format("\nTotal runtime %0.4fs", (t2 - t1)))
@@ -12,11 +12,12 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = %q{A simple tool to analyze footprint of Ruby requires.}
13
13
  spec.homepage = "https://github.com/irvingwashington/gem_footprint_analyzer"
14
14
  spec.license = "MIT"
15
+ spec.required_ruby_version = '>= 2.2.0'
15
16
 
16
17
  # Specify which files should be added to the gem when it is released.
17
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
19
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec/|\.)}) }
20
21
  end
21
22
  spec.bindir = "exe"
22
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -26,5 +27,5 @@ Gem::Specification.new do |spec|
26
27
  spec.add_development_dependency "rake", "~> 10.0"
27
28
  spec.add_development_dependency "rspec", "~> 3.0"
28
29
  spec.add_development_dependency "rubocop", "~> 0.60.0"
29
- spec.add_development_dependency "rubocop-rspec"
30
+ spec.add_development_dependency "rubocop-rspec", "~> 1.30"
30
31
  end
@@ -5,16 +5,17 @@ module GemFootprintAnalyzer
5
5
  # Require calls are interwoven with RSS checks done from the parent process, require timing
6
6
  # is gathered in the child process and passed along to the parent.
7
7
  class Analyzer
8
+ # @param fifos [Hash<Symbol>] Hash containing filenames of :child and :parent FIFO files
9
+ def initialize(fifos)
10
+ @fifos = fifos
11
+ end
12
+
8
13
  # @param library [String] name of the library or parameter for the gem method
9
14
  # (ex. 'activerecord', 'activesupport')
10
15
  # @param require_string [String|nil] optional require string, if it differs from the gem name
11
16
  # (ex. 'active_record', 'active_support/time')
12
17
  # @return [Array<Hash>] list of require-data-hashes, first element contains base level RSS,
13
18
  # last element can be treated as a summary as effectively it consists of all the previous.
14
- def initialize(fifos)
15
- @fifos = fifos
16
- end
17
-
18
19
  def test_library(library, require_string = nil)
19
20
  child = ChildProcess.new(library, require_string, fifos)
20
21
  child.start_child
@@ -16,10 +16,7 @@ module GemFootprintAnalyzer
16
16
  # @return [Array<Hash>] Array of hashes that now include average metrics in place of fields
17
17
  # present in {AVERAGED_FIELDS}. The rest of the columns is copied from the first sample.
18
18
  def run
19
- results = []
20
- @runs.times do
21
- results << run_once
22
- end
19
+ results = Array.new(@runs) { run_once }
23
20
  calculate_averages(results)
24
21
  end
25
22
 
@@ -50,8 +47,8 @@ module GemFootprintAnalyzer
50
47
  sum = values.sum.to_f
51
48
  mean = sum / num
52
49
 
53
- stddev = Math.sqrt(values.sum { |v| (v - mean)**2 } / num)
54
- {mean: mean, sttdev: stddev}
50
+ stddev = Math.sqrt(values.sum { |v| (v - mean)**2 } / num).round(4)
51
+ {mean: mean, stddev: stddev}
55
52
  end
56
53
 
57
54
  def initialize_average_with_copied_fields(sample)
@@ -20,7 +20,9 @@ module GemFootprintAnalyzer
20
20
  begin
21
21
  require(require_string)
22
22
  rescue LoadError => e
23
+ warn_about_load_error(e)
23
24
  transport.exit_with_error(e)
25
+ exit 1
24
26
  end
25
27
  transport.done_and_wait_for_ack
26
28
  end
@@ -52,6 +54,16 @@ module GemFootprintAnalyzer
52
54
  STDOUT.puts(message)
53
55
  STDOUT.flush
54
56
  end
57
+
58
+ def warn_about_load_error(error)
59
+ possible_gem = error.message.split.last
60
+ STDERR.puts "Cannot load '#{possible_gem}', this might be an issue with implicit require in" \
61
+ " the '#{require_string}'"
62
+ STDERR.puts "If '#{possible_gem}' is a gem, you can try adding it to the Gemfile explicitly" \
63
+ ", running `bundle install` and trying again\n\n"
64
+ STDERR.puts error.backtrace
65
+ STDERR.flush
66
+ end
55
67
  end
56
68
  end
57
69
 
@@ -4,6 +4,7 @@ require 'rbconfig'
4
4
  module GemFootprintAnalyzer
5
5
  # A class for starting the child process that does actual requires.
6
6
  class ChildProcess
7
+ LEGACY_RUBY_CMD = [RbConfig.ruby, '--disable=gem'].freeze
7
8
  RUBY_CMD = [RbConfig.ruby, '--disable=did_you_mean', '--disable=gem'].freeze
8
9
 
9
10
  def initialize(library, require_string, fifos)
@@ -15,11 +16,11 @@ module GemFootprintAnalyzer
15
16
 
16
17
  def start_child
17
18
  @child_thread ||= Thread.new do # rubocop:disable Naming/MemoizedInstanceVariableName
18
- Open3.popen3(child_env_vars, *RUBY_CMD, context_file) do |_, stdout, stderr|
19
+ Open3.popen3(child_env_vars, *ruby_command, context_file) do |_, stdout, stderr|
19
20
  @pid = stdout.gets.strip.to_i
20
21
 
21
22
  while (line = stderr.gets)
22
- puts "!! #{line.strip}"
23
+ print "!! #{line}"
23
24
  end
24
25
  end
25
26
  end
@@ -29,7 +30,6 @@ module GemFootprintAnalyzer
29
30
  return unless child_thread
30
31
 
31
32
  sleep 0.01 while @pid.nil?
32
-
33
33
  @pid
34
34
  end
35
35
 
@@ -37,6 +37,14 @@ module GemFootprintAnalyzer
37
37
 
38
38
  attr_reader :require_string, :child_thread, :fifos
39
39
 
40
+ def ruby_command
41
+ if RbConfig::CONFIG['MAJOR'].to_i >= 2 && RbConfig::CONFIG['MINOR'].to_i >= 3
42
+ RUBY_CMD
43
+ else
44
+ LEGACY_RUBY_CMD
45
+ end
46
+ end
47
+
40
48
  def child_env_vars
41
49
  {
42
50
  'require_string' => require_string,
@@ -3,7 +3,7 @@ module GemFootprintAnalyzer
3
3
  # Provides File#mkfifo, missing in Ruby 2.2.0
4
4
  module File
5
5
  def mkfifo(name)
6
- system("mkfifo #{name}")
6
+ system("mkfifo #{name}") || fail('Failed to make FIFO special file')
7
7
  end
8
8
  end
9
9
  end
@@ -11,7 +11,8 @@ module GemFootprintAnalyzer
11
11
  # Displays explanatory words for text formatter results
12
12
  def info
13
13
  lines = []
14
- lines << "GemFootprintAnalyzer (#{GemFootprintAnalyzer::VERSION})\n"
14
+ lines << "GemFootprintAnalyzer (#{GemFootprintAnalyzer::VERSION})"
15
+ lines << (debug? ? "(#{File.expand_path(File.join(File.dirname(__FILE__), '..'))})\n" : '')
15
16
  lines << "Analyze results (average measured from #{@options[:runs]} run(s))"
16
17
  lines << 'time is the amount of time given require has taken to complete'
17
18
  lines << 'RSS is total memory increase up to the point after the require'
@@ -23,6 +24,12 @@ module GemFootprintAnalyzer
23
24
  def dash(length)
24
25
  '-' * length
25
26
  end
27
+
28
+ private
29
+
30
+ def debug?
31
+ @options[:debug]
32
+ end
26
33
  end
27
34
  end
28
35
  end
@@ -7,9 +7,9 @@ module GemFootprintAnalyzer
7
7
  INDENT = ' '.freeze
8
8
  # Formatter helper class representing a single results require entry.
9
9
  class Entry
10
- def initialize(entry_hash, _options = {})
10
+ def initialize(entry_hash, options = {})
11
11
  @entry_hash = entry_hash
12
- @options = {}
12
+ @options = options
13
13
  end
14
14
 
15
15
  def name
@@ -39,7 +39,7 @@ module GemFootprintAnalyzer
39
39
  def debug_parent
40
40
  return unless @options[:debug]
41
41
 
42
- "(#{parent})"
42
+ " (#{parent})"
43
43
  end
44
44
  end
45
45
 
@@ -53,12 +53,13 @@ module GemFootprintAnalyzer
53
53
  private
54
54
 
55
55
  def formatted_entries(entries)
56
- indent_levels, max_indent = count_indent_levels(entries)
57
- max_name_length = entries.map { |e| e.name.length }.max
56
+ max_indent = max_indent(entries)
57
+ max_name_length = entries.map { |e| e.formatted_name.length }.max
58
58
  ljust_value = max_name_length + max_indent + 1
59
59
 
60
60
  lines = entries.reverse.map do |entry|
61
- format_entry(entry, indent_levels, ljust_value)
61
+ indent_level = count_indent_level(entry)
62
+ format_entry(entry, indent_level, ljust_value)
62
63
  end
63
64
 
64
65
  (legend(ljust_value) + lines).join("\n")
@@ -71,8 +72,8 @@ module GemFootprintAnalyzer
71
72
  ]
72
73
  end
73
74
 
74
- def format_entry(entry, indent_levels, ljust_value)
75
- indent = INDENT * indent_levels[entry.name]
75
+ def format_entry(entry, indent_level, ljust_value)
76
+ indent = INDENT * indent_level
76
77
  time = format('%5dms', entry.time)
77
78
  rss = format('%7dKB', entry.rss)
78
79
 
@@ -85,6 +86,22 @@ module GemFootprintAnalyzer
85
86
  end
86
87
  end
87
88
 
89
+ def max_indent(entries)
90
+ entries.reverse_each { |entry| count_indent_level(entry) }
91
+ max_indent_level = @indent_levels.map(&:values).flatten.max
92
+ @indent_levels = []
93
+ max_indent_level * INDENT.size
94
+ end
95
+
96
+ def count_indent_level(entry)
97
+ @indent_levels ||= []
98
+ parent_hash = @indent_levels.find { |elem| elem.key?(entry.parent) }
99
+ parent_level = parent_hash ? parent_hash.values.first : -1
100
+ indent_level = parent_level + 1
101
+ @indent_levels.unshift(entry.name => indent_level)
102
+ indent_level
103
+ end
104
+
88
105
  def count_indent_levels(entries)
89
106
  root = entries.last
90
107
  indent_levels = {root.name => 0}
@@ -15,11 +15,15 @@ module GemFootprintAnalyzer
15
15
  full_path.sub(%r{\A#{load_path}/}, '')
16
16
  end
17
17
 
18
- def first_foreign_caller(caller)
19
- ffc = caller.find do |c|
20
- GemFootprintAnalyzer::RequireSpy.relative_path(c) !~ /gem_footprint_analyzer/
18
+ def without_extension(name)
19
+ name.sub(/\.rb\z/, '')
20
+ end
21
+
22
+ def first_foreign_caller(caller_list)
23
+ ffc = caller_list.find do |c|
24
+ relative_path(c) !~ /gem_footprint_analyzer/
21
25
  end
22
- GemFootprintAnalyzer::RequireSpy.relative_path(ffc).sub(/\.rb\z/, '') if ffc
26
+ without_extension(relative_path(ffc)) if ffc
23
27
  end
24
28
 
25
29
  def spy_require(transport)
@@ -37,9 +41,9 @@ module GemFootprintAnalyzer
37
41
 
38
42
  def define_timed_exec
39
43
  Kernel.send :define_method, :timed_exec do |&block|
40
- start_time = Time.now.to_f
44
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
41
45
  block.call
42
- (Time.now.to_f - start_time).round(4)
46
+ (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time).round(4)
43
47
  end
44
48
  end
45
49
 
@@ -53,7 +57,8 @@ module GemFootprintAnalyzer
53
57
  t = timed_exec { result = regular_require(name) }
54
58
 
55
59
  first_foreign_caller = GemFootprintAnalyzer::RequireSpy.first_foreign_caller(caller)
56
- transport.report_require(name, first_foreign_caller || '', t)
60
+ bare_name = GemFootprintAnalyzer::RequireSpy.without_extension(name)
61
+ transport.report_require(bare_name, first_foreign_caller || '', t)
57
62
  result
58
63
  end
59
64
  end
@@ -9,7 +9,7 @@ module GemFootprintAnalyzer
9
9
  @write_stream = write_stream
10
10
  end
11
11
 
12
- # @return [Array] A tuple with command and *payload
12
+ # @return [Array|nil] A tuple with command and *payload or nil when command not recognized
13
13
  def read_one_command
14
14
  case read_raw_command
15
15
  when /\A(done|ack|start|ready)\z/
@@ -1,3 +1,3 @@
1
1
  module GemFootprintAnalyzer
2
- VERSION = '0.1.5'.freeze
2
+ VERSION = '0.1.6'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_footprint_analyzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciek Dubiński
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-03 00:00:00.000000000 Z
11
+ date: 2018-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: rubocop-rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '1.30'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '1.30'
83
83
  description:
84
84
  email:
85
85
  - maciek@dubinski.net
@@ -88,11 +88,6 @@ executables:
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
- - ".gitignore"
92
- - ".rspec"
93
- - ".rubocop"
94
- - ".rubocop.yml"
95
- - ".travis.yml"
96
91
  - CODE_OF_CONDUCT.md
97
92
  - Gemfile
98
93
  - Gemfile.lock
@@ -128,7 +123,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
123
  requirements:
129
124
  - - ">="
130
125
  - !ruby/object:Gem::Version
131
- version: '0'
126
+ version: 2.2.0
132
127
  required_rubygems_version: !ruby/object:Gem::Requirement
133
128
  requirements:
134
129
  - - ">="
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop DELETED
File without changes
@@ -1,22 +0,0 @@
1
- require: rubocop-rspec
2
- AllCops:
3
- Include:
4
- - 'lib/gem_footprint_analyzer/**/*.rb'
5
- - 'exe/*'
6
- - 'spec/**/*'
7
- TargetRubyVersion: 2.2
8
-
9
- Metrics/LineLength:
10
- Max: 100
11
-
12
- Style/RegexpLiteral:
13
- EnforcedStyle: slashes
14
-
15
- Layout/SpaceInsideHashLiteralBraces:
16
- EnforcedStyle: no_space
17
-
18
- Style/SignalException:
19
- EnforcedStyle: semantic
20
-
21
- RSpec/NestedGroups:
22
- Max: 5
@@ -1,14 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.5.3
7
- - 2.2
8
- before_install:
9
- - gem install bundler -v 1.17.1
10
- script:
11
- - bundle exec rubocop
12
- - bundle exec rspec
13
- - bundle exec analyze_requires -d rubocop
14
- - bundle exec analyze_requires net/http