memory_profiler 0.9.4 → 0.9.5

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
  SHA1:
3
- metadata.gz: 841f12f37a8d6ee73594fc0e9ab8718a1d79fb01
4
- data.tar.gz: ecb6925b365225274bfca91f11161d9dd83cd5d9
3
+ metadata.gz: f7e1c880efe5b674c1d8281a7f8659ca224abafe
4
+ data.tar.gz: 37e0a418e082d1fd1af188a0966efdc9e97c92d8
5
5
  SHA512:
6
- metadata.gz: 87d5d6cb856bf78f196edef91c06d04ab8ad239d2c124cb1233ceeb90e8363a0deaccfd1a00d10ad68290e84b008ae83e9312fbb6b6a89d1fe433edb7aeb72b5
7
- data.tar.gz: 68125449269c55e6f9e18299ba43bd4d743eb3f5a3e49558b7d7ef2b339a8942355678480ee52f40d72d74512cb347c5bad17ff9fd1f81d357f19ee4d10cb9f9
6
+ metadata.gz: e900a6abc28f73ceffc12dae74ba7cb416c53930b5eb9703d00b25a075afda2f9137f6a4f52f6958b91b9afa057c9fc4845227517c147226a1ab99de7dc384c3
7
+ data.tar.gz: 915bd319992cbfa7ba1f38a64ae8a5e83358a1bb390f67ac283dfe70cab03463e1698e869a73641f563c4a9aaa29d5b0732049e29341d46c4de1d61f042b2089
data/README.md CHANGED
@@ -35,7 +35,14 @@ report.pretty_print
35
35
 
36
36
  ## Options
37
37
 
38
- You can use `allow_files` option for displaying only lines which contain string or array with strings:
38
+ The report method can take a few options:
39
+
40
+ * `top`: maximum number of entries to display in a report (default is 50)
41
+ * `allow_files`: include only certain files from tracing - can be given as a String, Regexp, or array of Strings
42
+ * `ignore_files`: exclude certain files from tracing - can be given as a String or Regexp
43
+ * `trace`: an array of classes for which you explicitly want to trace object allocations
44
+
45
+ Check out `Reporter#new` for more details.
39
46
 
40
47
  ```
41
48
  pry> require 'memory_profiler'
@@ -77,14 +84,6 @@ rubygems x 305879
77
84
  . . .
78
85
  ```
79
86
 
80
- Other options include:
81
-
82
- * `top`: maximum number of entries to display in a report
83
- * `trace`: an array of classes for which you explicitly want to trace object allocations
84
- * `ignore_files`: a regular expression used to exclude certain files from tracing (opposite of `allow_files`)
85
-
86
- Check out `Reporter#new` for more details.
87
-
88
87
  ## Example Session
89
88
 
90
89
  You can easily use memory_profiler to profile require impact of a gem, for example:
@@ -366,6 +365,9 @@ Memory profiler also performs some String analysis to help you find strings that
366
365
 
367
366
  ## Changelog
368
367
 
368
+ ### 0.9.5
369
+ - Improved stability and performance @dgynn
370
+
369
371
  ### 0.9.4
370
372
  - FIX: remove incorrect RVALUE offset on 2.2 @dgynn
371
373
  - FEATURE: add total memory usage @dgynn
@@ -380,7 +382,6 @@ Memory profiler also performs some String analysis to help you find strings that
380
382
  - This is quite stable, upping version to reflect
381
383
  - Fixed bug where it would crash when location was nil for some reason
382
384
 
383
-
384
385
  ### 0.0.4
385
386
  - Added compatibility with released version of Ruby 2.1.0
386
387
  - Cleanup to use latest APIs available in 2.1.0
@@ -1,37 +1,32 @@
1
1
  module MemoryProfiler
2
- module Helpers
3
- def self.guess_gem(path)
4
- if /(\/gems\/.*)*\/gems\/(?<gem>[^\/]+)/ =~ path
5
- gem
6
- elsif /\/rubygems\// =~ path
7
- "rubygems"
8
- elsif /(?<app>[^\/]+\/(bin|app|lib))/ =~ path
9
- app
10
- else
11
- "other"
12
- end
2
+ class Helpers
3
+
4
+ def initialize
5
+ @gem_guess_cache = Hash.new
6
+ @location_cache = Hash.new { |h,k| h[k] = Hash.new.compare_by_identity }
7
+ @class_name_cache = Hash.new.compare_by_identity
13
8
  end
14
9
 
15
- # helper to work around GC.start not freeing everything
16
- def self.full_gc
17
- # TODO: discuss with @tmm1 and @ko1 if the while loop is needed
18
- GC.start(full_mark: true) while new_count = decreased_count(new_count)
10
+ def guess_gem(path)
11
+ @gem_guess_cache[path] ||=
12
+ if /(\/gems\/.*)*\/gems\/(?<gemname>[^\/]+)/ =~ path
13
+ gemname
14
+ elsif /\/rubygems[\.\/]/ =~ path
15
+ "rubygems".freeze
16
+ elsif /(?<app>[^\/]+\/(bin|app|lib))/ =~ path
17
+ app
18
+ else
19
+ "other".freeze
20
+ end
19
21
  end
20
22
 
21
- def self.decreased_count(old)
22
- count = count_objects
23
- if !old || count < old
24
- count
25
- else
26
- nil
27
- end
23
+ def lookup_location(file, line)
24
+ @location_cache[file][line] ||= "#{file}:#{line}"
28
25
  end
29
26
 
30
- def self.count_objects
31
- i = 0
32
- ObjectSpace.each_object do |obj|
33
- i += 1
34
- end
27
+ def lookup_class_name(klass)
28
+ @class_name_cache[klass] ||= klass.name || '<<Unknown>>'
35
29
  end
30
+
36
31
  end
37
32
  end
@@ -1,9 +1,8 @@
1
1
  require 'objspace'
2
2
  module MemoryProfiler
3
- # Reporter is the top level api used for generating memory reports
3
+ # Reporter is the top level API used for generating memory reports.
4
4
  #
5
5
  # @example Measure object allocation in a block
6
- #
7
6
  # report = Reporter.report(top: 50) do
8
7
  # 5.times { "foo" }
9
8
  # end
@@ -12,84 +11,71 @@ module MemoryProfiler
12
11
 
13
12
  def initialize(opts = {})
14
13
  @top = opts[:top] || 50
15
- @trace = opts[:trace]
16
- @ignore_files = opts[:ignore_files]
17
- @allow_files = Array(opts[:allow_files])
14
+ @trace = opts[:trace] && Array(opts[:trace])
15
+ @ignore_files = opts[:ignore_files] && Regexp.new(opts[:ignore_files])
16
+ @allow_files = opts[:allow_files] && /#{Array(opts[:allow_files]).join('|')}/
18
17
  end
19
18
 
20
- # Helper for generating new reporter and running against block
19
+ # Helper for generating new reporter and running against block.
20
+ # @param [Hash] opts the options to create a report with
21
+ # @option opts :top max number of entries to output
22
+ # @option opts :trace a class or an array of classes you explicitly want to trace
23
+ # @option opts :ignore_files a regular expression used to exclude certain files from tracing
24
+ # @option opts :allow_files a string or array of strings to selectively include in tracing
25
+ # @return [MemoryProfiler::Results]
21
26
  def self.report(opts={}, &block)
22
27
  self.new(opts).run(&block)
23
28
  end
24
29
 
25
30
  # Collects object allocation and memory of ruby code inside of passed block.
26
- #
27
- # @param [Hash] opts the options to create a message with.
28
- # @option opts [Fixnum] :top max number of entries to output in report
29
- # @option opts [Array <Class>] :trace an array of classes you explicitly want to trace
30
- # @return [MemoryProfiler::Results]
31
31
  def run(&block)
32
32
 
33
- allocated, rvalue_size = nil
34
-
35
- rvalue_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
36
- Helpers.full_gc
33
+ GC.start
37
34
  GC.disable
38
35
 
36
+ generation = GC.count
39
37
  ObjectSpace.trace_object_allocations do
40
- generation = GC.count
41
38
  block.call
42
- allocated = object_list(generation, rvalue_size)
43
39
  end
44
-
45
- results = Results.new
46
- results.strings_allocated = results.string_report(allocated, top)
40
+ allocated = object_list(generation)
41
+ retained = StatHash.new.compare_by_identity
47
42
 
48
43
  GC.enable
44
+ GC.start
49
45
 
50
- Helpers.full_gc
46
+ # Caution: Do not allocate any new Objects between the call to GC.start and the completion of the retained
47
+ # lookups. It is likely that a new Object would reuse an object_id from a GC'd object.
51
48
 
52
- retained = StatHash.new
53
49
  ObjectSpace.each_object do |obj|
50
+ next unless ObjectSpace.allocation_generation(obj) == generation
54
51
  begin
55
52
  found = allocated[obj.__id__]
56
53
  retained[obj.__id__] = found if found
57
54
  rescue
58
55
  # __id__ is not defined on BasicObject, skip it
59
- # we can probably trasplant the object_id at this point,
56
+ # we can probably transplant the object_id at this point,
60
57
  # but it is quite rare
61
58
  end
62
59
  end
60
+ ObjectSpace.trace_object_allocations_clear
63
61
 
62
+ results = Results.new
64
63
  results.register_results(allocated, retained, top)
65
64
  results
66
65
  end
67
66
 
68
- def trace_all?
69
- !trace
70
- end
71
-
72
- def ignore_file?(file)
73
- return true if file == __FILE__
74
- @ignore_files && @ignore_files =~ file
75
- end
76
-
77
- def allow_file?(file)
78
- return true if @allow_files.empty?
79
- !/#{@allow_files.join('|')}/.match(file).to_s.empty?
80
- end
67
+ private
81
68
 
82
69
  # Iterates through objects in memory of a given generation.
83
70
  # Stores results along with meta data of objects collected.
84
- def object_list(generation, rvalue_size)
71
+ def object_list(generation)
85
72
 
86
- results = StatHash.new
87
73
  objs = []
88
74
 
89
75
  ObjectSpace.each_object do |obj|
90
- next unless generation == ObjectSpace.allocation_generation(obj)
76
+ next unless ObjectSpace.allocation_generation(obj) == generation
91
77
  begin
92
- if trace_all? || trace.include?(obj.class)
78
+ if !trace || trace.include?(obj.class)
93
79
  objs << obj
94
80
  end
95
81
  rescue
@@ -97,29 +83,40 @@ module MemoryProfiler
97
83
  end
98
84
  end
99
85
 
86
+ rvalue_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
87
+ rvalue_size_adjustment = RUBY_VERSION < '2.2' ? rvalue_size : 0
88
+ helper = Helpers.new
89
+
90
+ result = StatHash.new.compare_by_identity
91
+
100
92
  objs.each do |obj|
101
- file = ObjectSpace.allocation_sourcefile(obj)
102
- next if !allow_file?(file) || ignore_file?(file)
93
+ file = ObjectSpace.allocation_sourcefile(obj) || "(no name)".freeze
94
+ next if @ignore_files && @ignore_files =~ file
95
+ next if @allow_files && !(@allow_files =~ file)
103
96
 
104
97
  line = ObjectSpace.allocation_sourceline(obj)
105
- class_path = ObjectSpace.allocation_class_path(obj)
106
- method_id = ObjectSpace.allocation_method_id(obj)
98
+ location = helper.lookup_location(file, line)
99
+ klass = obj.class
100
+ class_name = helper.lookup_class_name(klass)
101
+ gem = helper.guess_gem(file)
102
+ string = '' << obj if klass == String
107
103
 
108
- class_name = obj.class.name rescue "BasicObject"
109
104
  begin
110
105
  object_id = obj.__id__
111
106
 
112
- memsize = ObjectSpace.memsize_of(obj)
113
- memsize += rvalue_size if RUBY_VERSION < '2.2'.freeze
107
+ memsize = ObjectSpace.memsize_of(obj) + rvalue_size_adjustment
114
108
  # compensate for API bug
115
109
  memsize = rvalue_size if memsize > 100_000_000_000
116
- results[object_id] = Stat.new(class_name, file, line, class_path, method_id, memsize)
110
+ result[object_id] = MemoryProfiler::Stat.new(class_name, gem, file, location, memsize, string)
117
111
  rescue
118
112
  # __id__ is not defined, give up
119
113
  end
120
114
  end
121
115
 
122
- results
116
+ # Although `objs` will go out of scope, clear the array so objects can definitely be GCd
117
+ objs.clear
118
+
119
+ result
123
120
  end
124
121
  end
125
122
  end
@@ -1,89 +1,69 @@
1
1
  module MemoryProfiler
2
2
  class Results
3
3
 
4
- def self.register_type(name, lookup)
5
- ["allocated", "retained"].product(["objects", "memory"]).each do |type, metric|
6
- full_name = "#{type}_#{metric}_by_#{name}"
7
- attr_accessor full_name
8
-
9
- @@lookups ||= []
10
- mapped = lookup
11
-
12
- if metric == "memory"
13
- mapped = lambda { |stat|
14
- [lookup.call(stat), stat.memsize]
15
- }
16
- end
17
-
18
- @@lookups << [full_name, mapped]
4
+ def self.register_type(name, stat_attribute)
5
+ @@lookups ||= []
6
+ @@lookups << [name, stat_attribute]
19
7
 
8
+ ["allocated", "retained"].product(["objects", "memory"]).each do |type, metric|
9
+ attr_accessor "#{type}_#{metric}_by_#{name}"
20
10
  end
21
11
  end
22
12
 
23
- register_type :gem, lambda { |stat|
24
- Helpers.guess_gem("#{stat.file}")
25
- }
26
-
27
- register_type :file, lambda { |stat|
28
- stat.file || "(no name)"
29
- }
30
-
31
- register_type :location, lambda { |stat|
32
- "#{stat.file}:#{stat.line}"
33
- }
34
-
35
- register_type :class, lambda { |stat|
36
- "#{stat.class_name}"
37
- }
13
+ register_type 'gem', :gem
14
+ register_type 'file', :file
15
+ register_type 'location', :location
16
+ register_type 'class', :class_name
38
17
 
39
18
  attr_accessor :strings_retained, :strings_allocated
40
19
  attr_accessor :total_retained, :total_allocated
41
20
  attr_accessor :total_retained_memsize, :total_allocated_memsize
42
21
 
43
- def self.from_raw(allocated, retained, top)
44
- self.new.register_results(allocated, retained, top)
45
- end
46
-
47
22
  def register_results(allocated, retained, top)
48
- @@lookups.each do |name, lookup|
49
- mapped = lambda { |tuple|
50
- lookup.call(tuple[1])
51
- }
52
-
53
- result =
54
- if name =~ /^allocated/
55
- allocated.top_n(top, &mapped)
56
- else
57
- retained.top_n(top, &mapped)
58
- end
59
-
60
- self.send "#{name}=", result
23
+
24
+ @@lookups.each do |name, stat_attribute|
25
+
26
+ memsize_results, count_results = allocated.top_n(top, stat_attribute)
27
+
28
+ self.send("allocated_memory_by_#{name}=", memsize_results)
29
+ self.send("allocated_objects_by_#{name}=", count_results)
30
+
31
+ memsize_results, count_results = retained.top_n(top, stat_attribute)
32
+
33
+ self.send("retained_memory_by_#{name}=", memsize_results)
34
+ self.send("retained_objects_by_#{name}=", count_results)
61
35
  end
62
36
 
37
+
38
+ self.strings_allocated = string_report(allocated, top)
63
39
  self.strings_retained = string_report(retained, top)
64
40
 
65
- self.total_allocated = allocated.count
66
- self.total_allocated_memsize = allocated.values.map(&:memsize).inject(:+) || 0
67
- self.total_retained = retained.count
68
- self.total_retained_memsize = retained.values.map(&:memsize).inject(:+) || 0
41
+ self.total_allocated = allocated.size
42
+ self.total_allocated_memsize = allocated.values.map!(&:memsize).inject(0, :+)
43
+ self.total_retained = retained.size
44
+ self.total_retained_memsize = retained.values.map!(&:memsize).inject(0, :+)
69
45
 
70
46
  self
71
47
  end
72
48
 
73
- StringStat = Struct.new(:string, :count, :location)
74
-
75
49
  def string_report(data, top)
76
- data
77
- .reject { |id, stat| stat.class_name != "String" }
78
- .map { |id, stat| [begin; ObjectSpace._id2ref(id); rescue; "__UNKNOWN__"; end, "#{stat.file}:#{stat.line}"] }
79
- .group_by { |string, location| string }
80
- .sort_by { |string, list| -list.count }
50
+ data.values
51
+ .keep_if { |stat| stat.string_value }
52
+ .map! { |stat| [stat.string_value, stat.location] }
53
+ .group_by { |string, _location| string }
54
+ .sort_by {|string, list| [-list.size, string] }
81
55
  .first(top)
82
- .map { |string, list| [string, list.group_by { |str, location| location }
83
- .map { |location, locations| [location, locations.count] }] }
56
+ .map { |string, list| [string, list.group_by { |_string, location| location }
57
+ .map { |location, locations| [location, locations.size] }
58
+ ]
59
+ }
84
60
  end
85
61
 
86
- def pretty_print(io = STDOUT, **options)
62
+ # Output the results of the report
63
+ # @param [Hash] options the options for output
64
+ # @option opts [String] :to_file a path to your log file
65
+ # @option opts [Boolean] :color_output a flag for whether to colorize output
66
+ def pretty_print(io = STDOUT, options = {})
87
67
  io = File.open(options[:to_file], "w") if options[:to_file]
88
68
 
89
69
  color_output = options.fetch(:color_output) { io.respond_to?(:isatty) && io.isatty }
@@ -116,7 +96,7 @@ module MemoryProfiler
116
96
  io.puts @colorize.line("-----------------------------------")
117
97
  strings.each do |string, stats|
118
98
  io.puts "#{stats.reduce(0) { |a, b| a + b[1] }.to_s.rjust(10)} #{@colorize.string((string[0..200].inspect))}"
119
- stats.sort_by { |x, y| -y }.each do |location, count|
99
+ stats.sort_by { |x, y| [-y, x] }.each do |location, count|
120
100
  io.puts "#{@colorize.path(count.to_s.rjust(10))} #{location}"
121
101
  end
122
102
  io.puts
@@ -127,7 +107,7 @@ module MemoryProfiler
127
107
  def dump(description, data, io)
128
108
  io.puts description
129
109
  io.puts @colorize.line("-----------------------------------")
130
- if data
110
+ if data && !data.empty?
131
111
  data.each do |item|
132
112
  io.puts "#{item[:count].to_s.rjust(10)} #{item[:data]}"
133
113
  end
@@ -1,3 +1,18 @@
1
1
  module MemoryProfiler
2
- Stat = Struct.new(:class_name, :file, :line, :class_path, :method_id, :memsize)
2
+ class Stat
3
+
4
+ attr_reader :class_name, :gem, :file, :location, :memsize, :string_value
5
+
6
+ def initialize(class_name, gem, file, location, memsize, string_value)
7
+ @class_name = class_name
8
+ @gem = gem
9
+
10
+ @file = file
11
+ @location = location
12
+
13
+ @memsize = memsize
14
+ @string_value = string_value
15
+ end
16
+
17
+ end
3
18
  end
@@ -1,54 +1,21 @@
1
1
  module MemoryProfiler
2
2
  module TopN
3
- # Efficient mechanism for finding top_n entries in a list
4
- # optional block can specify custom element and weight
5
- def top_n(max = 10)
3
+ # Fast approach for determining the top_n entries in a Hash of Stat objects.
4
+ # Returns results for both memory (memsize summed) and objects allocated (count) as a tuple.
5
+ def top_n(max, metric)
6
6
 
7
- sorted =
8
- if block_given?
9
- self.map { |row|
10
- yield(row)
11
- }
12
- else
13
- self.dup
14
- end
7
+ stats_by_metric = self.values.map! { |stat| [stat.send(metric), stat.memsize] }
15
8
 
16
- sorted.compact!
17
- sorted.sort!
9
+ stat_totals = stats_by_metric.group_by { |metric_value, _memsize| metric_value }.
10
+ map { |key, values| [key, values.reduce(0) { |sum, item| _key, memsize = item ; sum + memsize }, values.size] }
18
11
 
19
- found = []
12
+ stats_by_memsize = stat_totals.sort_by! { |metric, memsize, _count| [-memsize, metric] }.first(max).
13
+ map! { |metric, memsize, _count| { data: metric, count: memsize } }
14
+ stats_by_count = stat_totals.sort_by! { |metric, _memsize, count| [-count, metric] }.first(max).
15
+ map! { |metric, _memsize, count| { data: metric, count: count } }
20
16
 
21
- last = sorted[0]
22
- count = 0
23
- lowest_count = 0
17
+ [stats_by_memsize, stats_by_count]
24
18
 
25
- sorted << nil
26
-
27
- sorted.each do |row|
28
-
29
- current_item, current_count = row
30
-
31
- unless current_item == last
32
- if count > lowest_count
33
- found << {data: last, count: count}
34
- end
35
-
36
- if found.length > max
37
- found.sort!{|x,y| x[:count] <=> y[:count] }
38
- found.delete_at(0)
39
- lowest_count = found[0][:count]
40
- end
41
-
42
- count = 0
43
- last = current_item
44
- end
45
-
46
- count += (current_count || 1) unless row.nil?
47
- end
48
-
49
- found
50
- .sort!{|x,y| x[:count] <=> y[:count] }
51
- .reverse
52
19
  end
53
20
  end
54
21
  end
@@ -1,3 +1,3 @@
1
1
  module MemoryProfiler
2
- VERSION = "0.9.4"
2
+ VERSION = "0.9.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memory_profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-05 00:00:00.000000000 Z
11
+ date: 2015-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,20 +80,15 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: Memory profiling routines for Ruby Head
83
+ description: Memory profiling routines for Ruby 2.1+
84
84
  email:
85
85
  - sam.saffron@gmail.com
86
86
  executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
- - ".gitignore"
91
- - ".travis.yml"
92
- - Gemfile
93
- - Guardfile
94
90
  - LICENSE.txt
95
91
  - README.md
96
- - Rakefile
97
92
  - lib/memory_profiler.rb
98
93
  - lib/memory_profiler/helpers.rb
99
94
  - lib/memory_profiler/monochrome.rb
@@ -104,14 +99,7 @@ files:
104
99
  - lib/memory_profiler/stat_hash.rb
105
100
  - lib/memory_profiler/top_n.rb
106
101
  - lib/memory_profiler/version.rb
107
- - memory_profiler.gemspec
108
- - test/test_helper.rb
109
- - test/test_helpers.rb
110
- - test/test_reporter.rb
111
- - test/test_results.rb
112
- - test/test_stat_hash.rb
113
- - test/test_top_n.rb
114
- homepage: ''
102
+ homepage: https://github.com/SamSaffron/memory_profiler
115
103
  licenses:
116
104
  - MIT
117
105
  metadata: {}
@@ -123,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
111
  requirements:
124
112
  - - ">="
125
113
  - !ruby/object:Gem::Version
126
- version: '0'
114
+ version: 2.1.0
127
115
  required_rubygems_version: !ruby/object:Gem::Requirement
128
116
  requirements:
129
117
  - - ">="
@@ -131,14 +119,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
119
  version: '0'
132
120
  requirements: []
133
121
  rubyforge_project:
134
- rubygems_version: 2.4.5
122
+ rubygems_version: 2.4.5.1
135
123
  signing_key:
136
124
  specification_version: 4
137
- summary: Memory profiling routines for Ruby Head
138
- test_files:
139
- - test/test_helper.rb
140
- - test/test_helpers.rb
141
- - test/test_reporter.rb
142
- - test/test_results.rb
143
- - test/test_stat_hash.rb
144
- - test/test_top_n.rb
125
+ summary: Memory profiling routines for Ruby 2.1+
126
+ test_files: []
data/.gitignore DELETED
@@ -1,17 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.1.0
4
- script: 'bundle exec rake test'
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in memory_profiler.gemspec
4
- gemspec
data/Guardfile DELETED
@@ -1,7 +0,0 @@
1
- guard :minitest do
2
- # with Minitest::Unit
3
- watch(%r{^test/(.*)\/?test_(.*)\.rb$})
4
- watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/test_#{m[2]}.rb" }
5
- watch(%r{^test/test_helper\.rb$}) { 'test' }
6
-
7
- end
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new do |t|
5
- t.pattern = "test/test_*.rb"
6
- end
7
-
8
- task default: "test"
@@ -1,26 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'memory_profiler/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "memory_profiler"
8
- spec.version = MemoryProfiler::VERSION
9
- spec.authors = ["Sam Saffron"]
10
- spec.email = ["sam.saffron@gmail.com"]
11
- spec.description = %q{Memory profiling routines for Ruby Head}
12
- spec.summary = %q{Memory profiling routines for Ruby Head}
13
- spec.homepage = ""
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- spec.add_development_dependency "minitest"
24
- spec.add_development_dependency "guard"
25
- spec.add_development_dependency "guard-minitest"
26
- end
@@ -1,3 +0,0 @@
1
- require 'memory_profiler'
2
- require 'minitest/pride'
3
- require 'minitest/autorun'
@@ -1,32 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- module MemoryProfiler
4
-
5
- class TestHelpers < Minitest::Test
6
- def assert_gem_parse(expected, path)
7
- assert_equal(expected, Helpers.guess_gem(path))
8
- end
9
-
10
- def test_rubygems_parse
11
- assert_gem_parse( "rubygems",
12
- "/home/sam/.rbenv/versions/ruby-head/lib/ruby/2.1.0/rubygems/version.rb")
13
- end
14
-
15
- def test_standard_parse
16
- assert_gem_parse( "rails_multisite",
17
- "/home/sam/Source/discourse/vendor/gems/rails_multisite/lib")
18
- end
19
-
20
- def test_another_standard_parse
21
- assert_gem_parse( "activesupport-3.2.12",
22
- "/home/sam/.rbenv/versions/ruby-head/lib/ruby/gems/2.1.0/gems/activesupport-3.2.12/lib/active_support/dependencies.rb")
23
- end
24
-
25
- def test_app_path_parse
26
- assert_gem_parse( "discourse/app",
27
- "/home/sam/Source/discourse/app/assets")
28
- end
29
-
30
- end
31
-
32
- end
@@ -1,101 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestReporter < Minitest::Test
4
-
5
- class Foo; end
6
-
7
- def allocate_strings(n)
8
- n.times do
9
- ""
10
- end
11
- end
12
-
13
- def test_counts
14
- a = nil
15
- result = MemoryProfiler::Reporter.report do
16
- allocate_strings(10)
17
- a = "hello"
18
- end
19
- assert_equal(11, result.total_allocated)
20
- assert_equal(1, result.total_retained)
21
- assert_equal(1, result.retained_objects_by_location.length)
22
- end
23
-
24
- def test_class_tracing
25
- result = MemoryProfiler::Reporter.report(:trace => [Foo]) do
26
- "hello"
27
- "hello"
28
- Foo.new
29
- end
30
- assert_equal(1, result.total_allocated)
31
- assert_equal(0, result.total_retained)
32
- end
33
-
34
- def test_ignore_file
35
- result = MemoryProfiler::Reporter.report(:ignore_files => /test_reporter\.rb/) do
36
- "hello"
37
- "hello"
38
- Foo.new
39
- end
40
-
41
- assert_equal(0, result.total_allocated)
42
- assert_equal(0, result.total_retained)
43
- end
44
-
45
- def test_no_color_output
46
- report = MemoryProfiler::Reporter.report do
47
- allocate_strings(10)
48
- end
49
- io = StringIO.new
50
- report.pretty_print io, color_output: false
51
- assert(!io.string.include?("\033"), 'excludes color information')
52
- end
53
-
54
- def test_color_output
55
- report = MemoryProfiler::Reporter.report do
56
- allocate_strings(10)
57
- end
58
- io = StringIO.new
59
- report.pretty_print io, color_output: true
60
- assert(io.string.include?("\033"), 'includes color information')
61
- end
62
-
63
- class StdoutMock < StringIO
64
- def isatty
65
- true
66
- end
67
- end
68
-
69
- def test_color_output_defaults_to_true_when_run_from_tty
70
- report = MemoryProfiler::Reporter.report do
71
- allocate_strings(10)
72
- end
73
- io = StdoutMock.new
74
- report.pretty_print io
75
- assert(io.string.include?("\033"), 'includes color information')
76
- end
77
-
78
- def test_mono_output_defaults_to_true_when_not_run_from_tty
79
- report = MemoryProfiler::Reporter.report do
80
- allocate_strings(10)
81
- end
82
- io = StringIO.new
83
- report.pretty_print io
84
- assert(!io.string.include?("\033"), 'excludes color information')
85
- end
86
-
87
- def test_reports_can_be_reused_with_different_color_options
88
- report = MemoryProfiler::Reporter.report do
89
- allocate_strings(10)
90
- end
91
-
92
- io = StringIO.new
93
- report.pretty_print io, color_output: true
94
- assert(io.string.include?("\033"), 'includes color information')
95
-
96
- io = StringIO.new
97
- report.pretty_print io, color_output: false
98
- assert(!io.string.include?("\033"), 'excludes color information')
99
- end
100
-
101
- end
@@ -1,9 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestResults < Minitest::Test
4
- def test_pretty_print_works
5
- io = StringIO.new
6
- MemoryProfiler::Results.new.pretty_print io
7
- end
8
-
9
- end
@@ -1,6 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestStatHash < Minitest::Test
4
-
5
-
6
- end
@@ -1,39 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class ArrayWithTopN < Array
4
- include MemoryProfiler::TopN
5
- end
6
-
7
- class TestTopN < Minitest::Test
8
-
9
- def tn(*vals)
10
- ArrayWithTopN.new.concat(vals)
11
- end
12
-
13
- def test_top_n
14
- data = tn( 7,1,2,2,3,3,99,3 )
15
- results = data.top_n(2)
16
-
17
- assert_equal([{data: 3, count: 3}, {data: 2, count: 2}], results)
18
- end
19
-
20
- def test_top_n_with_block
21
- data = tn( 0,3,6,1,4,2 )
22
-
23
- results = data.top_n(2) do |r|
24
- r%3
25
- end
26
-
27
- assert_equal([{data: 0, count: 3}, {data: 1, count: 2}], results)
28
- end
29
- def test_top_n_with_block_and_size
30
- data = tn( [1,100], [1,10], [2,1], [2,1], [2,1],[3,100] )
31
-
32
- results = data.top_n(2) do |r|
33
- r
34
- end
35
-
36
- assert_equal([{data: 1, count: 110}, {data: 3, count: 100}], results)
37
- end
38
-
39
- end