memory_profiler 0.9.4 → 0.9.5

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
  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