memprof2 0.0.1 → 0.0.2
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +38 -26
- data/lib/memprof2.rb +48 -29
- data/memprof2.gemspec +1 -1
- data/test/helper.rb +2 -0
- data/test/test_memprof2.rb +53 -0
- data/tmp/.gitkeep +0 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f7d49694ae39d219aa3825bdbdf5a5dffbae4ea
|
4
|
+
data.tar.gz: cf598a824cdbf2d424062f7b0a94e790ba8beacc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e31eaf801bff2ec8f2d39da44554be1c65f661d3eb46d53debff04243db77945b3883be0dd7af90a2ae64a24f1e292fd86126bd329566e57f8ce546ac338150d
|
7
|
+
data.tar.gz: 470ce1c09df87bc05f5635f532f1b9fadf692ae863115cdebad5c896331f8934cc4864ad013327d88d65eb6c3a70a571201726958de3b062082e25d5fd4be45f
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -28,35 +28,43 @@ $ bundle
|
|
28
28
|
|
29
29
|
## Memprof2.report
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
```ruby
|
32
|
+
Memprof2.start
|
33
|
+
12.times{ "abc" }
|
34
|
+
Memprof2.report(out: "/path/to/file")
|
35
|
+
Memprof2.stop
|
36
|
+
```
|
35
37
|
|
36
38
|
Start tracking file/line memory size (bytes) information for objects created after calling `Memprof2.start`, and print out a summary of file:line:class pairs created.
|
37
39
|
|
38
|
-
|
40
|
+
```
|
41
|
+
480 file.rb:2:String
|
42
|
+
```
|
39
43
|
|
40
44
|
*Note*: Call `Memprof2.report` again after `GC.start` to see which objects are cleaned up by the garbage collector:
|
41
45
|
|
42
|
-
|
43
|
-
|
46
|
+
```ruby
|
47
|
+
Memprof2.start
|
48
|
+
10.times{ $last_str = "abc" }
|
44
49
|
|
45
|
-
|
46
|
-
|
50
|
+
puts '=== Before GC'
|
51
|
+
Memprof2.report
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
53
|
+
puts '=== After GC'
|
54
|
+
GC.start
|
55
|
+
Memprof2.report
|
51
56
|
|
52
|
-
|
57
|
+
Memprof2.stop
|
58
|
+
```
|
53
59
|
|
54
60
|
After `GC.start`, only the very last instance of `"abc"` will still exist:
|
55
61
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
62
|
+
```
|
63
|
+
=== Before GC
|
64
|
+
400 file.rb:2:String
|
65
|
+
=== After GC
|
66
|
+
40 file.rb:2:String
|
67
|
+
```
|
60
68
|
|
61
69
|
*Note*: Use `Memprof2.report!` to clear out tracking data after printing out results.
|
62
70
|
|
@@ -64,18 +72,22 @@ After `GC.start`, only the very last instance of `"abc"` will still exist:
|
|
64
72
|
|
65
73
|
Simple wrapper for `Memprof2.start/stop` that will start/stop memprof around a given block of ruby code.
|
66
74
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
```ruby
|
76
|
+
Memprof2.run do
|
77
|
+
100.times{ "abc" }
|
78
|
+
100.times{ 1.23 + 1 }
|
79
|
+
100.times{ Module.new }
|
80
|
+
Memprof2.report(out: "/path/to/file")
|
81
|
+
end
|
82
|
+
```
|
73
83
|
|
74
84
|
For the block of ruby code, print out file:line:class pairs for ruby objects created.
|
75
85
|
|
76
|
-
|
77
|
-
|
78
|
-
|
86
|
+
```
|
87
|
+
4000 file.rb:2:String
|
88
|
+
4000 file.rb:3:Float
|
89
|
+
4000 file.rb:4:Module
|
90
|
+
```
|
79
91
|
|
80
92
|
*Note*: You can call GC.start at the end of the block to print out only objects that are 'leaking' (i.e. objects that still have inbound references).
|
81
93
|
|
data/lib/memprof2.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'objspace'
|
2
2
|
|
3
|
-
|
3
|
+
class Memprof2
|
4
4
|
class << self
|
5
5
|
def start
|
6
6
|
ObjectSpace.trace_object_allocations_start
|
@@ -15,38 +15,57 @@ module Memprof2
|
|
15
15
|
ObjectSpace.trace_object_allocations(&block)
|
16
16
|
end
|
17
17
|
|
18
|
-
def report(opts={})
|
18
|
+
def report(opts = {})
|
19
19
|
ObjectSpace.trace_object_allocations_stop
|
20
|
-
|
21
|
-
if @trace = opts[:trace]
|
22
|
-
raise ArgumentError, "`trace` option must be a Regexp object" unless @trace.is_a?(Regexp)
|
23
|
-
end
|
24
|
-
if @ignore = opts[:ignore]
|
25
|
-
raise ArgumentError, "`trace` option must be a Regexp object" unless @ignore.is_a?(Regexp)
|
26
|
-
end
|
27
|
-
results = {}
|
28
|
-
ObjectSpace.each_object do |o|
|
29
|
-
next unless (file = ObjectSpace.allocation_sourcefile(o))
|
30
|
-
next if file == __FILE__
|
31
|
-
next if (@trace and @trace !~ file)
|
32
|
-
next if (@ignore and @ignore =~ file)
|
33
|
-
line = ObjectSpace.allocation_sourceline(o)
|
34
|
-
memsize = ObjectSpace.memsize_of(o) + @rvalue_size
|
35
|
-
memsize = @rvalue_size if memsize > 100_000_000_000 # compensate for API bug
|
36
|
-
klass = o.class.name rescue "BasicObject"
|
37
|
-
location = "#{file}:#{line}:#{klass}"
|
38
|
-
results[location] ||= 0
|
39
|
-
results[location] += memsize
|
40
|
-
end
|
41
|
-
@out = opts[:out] || "/dev/stdout"
|
42
|
-
File.open(@out, 'w') do |io|
|
43
|
-
results.each do |location, memsize|
|
44
|
-
io.puts "#{memsize} #{location}"
|
45
|
-
end
|
46
|
-
end
|
20
|
+
self.new.report(opts)
|
47
21
|
ensure
|
48
22
|
ObjectSpace.trace_object_allocations_start
|
49
23
|
end
|
24
|
+
|
25
|
+
def report!(opts = {})
|
26
|
+
report(opts)
|
27
|
+
ObjectSpace.trace_object_allocations_clear
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def report(opts={})
|
32
|
+
configure(opts)
|
33
|
+
results = collect_info
|
34
|
+
File.open(@out, 'w') do |io|
|
35
|
+
results.each do |location, memsize|
|
36
|
+
io.puts "#{memsize} #{location}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def configure(opts = {})
|
42
|
+
@rvalue_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
|
43
|
+
if @trace = opts[:trace]
|
44
|
+
raise ArgumentError, "`trace` option must be a Regexp object" unless @trace.is_a?(Regexp)
|
45
|
+
end
|
46
|
+
if @ignore = opts[:ignore]
|
47
|
+
raise ArgumentError, "`ignore` option must be a Regexp object" unless @ignore.is_a?(Regexp)
|
48
|
+
end
|
49
|
+
@out = opts[:out] || "/dev/stdout"
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def collect_info
|
54
|
+
results = {}
|
55
|
+
ObjectSpace.each_object do |o|
|
56
|
+
next unless (file = ObjectSpace.allocation_sourcefile(o))
|
57
|
+
next if file == __FILE__
|
58
|
+
next if (@trace and @trace !~ file)
|
59
|
+
next if (@ignore and @ignore =~ file)
|
60
|
+
line = ObjectSpace.allocation_sourceline(o)
|
61
|
+
memsize = ObjectSpace.memsize_of(o) + @rvalue_size
|
62
|
+
memsize = @rvalue_size if memsize > 100_000_000_000 # compensate for API bug
|
63
|
+
klass = o.class.name rescue "BasicObject"
|
64
|
+
location = "#{file}:#{line}:#{klass}"
|
65
|
+
results[location] ||= 0
|
66
|
+
results[location] += memsize
|
67
|
+
end
|
68
|
+
results
|
50
69
|
end
|
51
70
|
end
|
52
71
|
|
data/memprof2.gemspec
CHANGED
data/test/helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestMemprof2 < Test::Unit::TestCase
|
4
|
+
def rvalue_size
|
5
|
+
GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
|
6
|
+
end
|
7
|
+
|
8
|
+
def find(results, key_match)
|
9
|
+
results.find {|k, v| k =~ key_match }.last
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_start_stop
|
13
|
+
memprof = Memprof2.new.configure({})
|
14
|
+
Memprof2.start
|
15
|
+
a = "abc"
|
16
|
+
12.times{ "abc" }
|
17
|
+
results = memprof.collect_info
|
18
|
+
Memprof2.stop
|
19
|
+
assert_equal(rvalue_size, find(results, /test_memprof2.rb:15:String/))
|
20
|
+
assert_equal(rvalue_size * 12, find(results, /test_memprof2.rb:16:String/))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_run
|
24
|
+
memprof = Memprof2.new.configure({})
|
25
|
+
results = nil
|
26
|
+
Memprof2.run do
|
27
|
+
a = "abc"
|
28
|
+
results = memprof.collect_info
|
29
|
+
end
|
30
|
+
assert_equal(rvalue_size, find(results, /test_memprof2.rb:27:String/))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_report_out
|
34
|
+
opts = {out: "tmp/test_report.out"}
|
35
|
+
Memprof2.start
|
36
|
+
a = "abc"
|
37
|
+
Memprof2.report(opts)
|
38
|
+
Memprof2.stop
|
39
|
+
assert_match("test/test_memprof2.rb:36:String\n", File.read(opts[:out]))
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_report!
|
43
|
+
opts_bang = {out: "tmp/test_report_bang.out"}
|
44
|
+
opts = {out: "tmp/test_report.out"}
|
45
|
+
Memprof2.start
|
46
|
+
a = "abc"
|
47
|
+
Memprof2.report!(opts_bang) # clear
|
48
|
+
Memprof2.report(opts)
|
49
|
+
Memprof2.stop
|
50
|
+
assert_match("test/test_memprof2.rb:46:String\n", File.read(opts_bang[:out]))
|
51
|
+
assert_match("", File.read(opts[:out]))
|
52
|
+
end
|
53
|
+
end
|
data/tmp/.gitkeep
ADDED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memprof2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naotoshi Seo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -55,6 +55,9 @@ files:
|
|
55
55
|
- example.rb
|
56
56
|
- lib/memprof2.rb
|
57
57
|
- memprof2.gemspec
|
58
|
+
- test/helper.rb
|
59
|
+
- test/test_memprof2.rb
|
60
|
+
- tmp/.gitkeep
|
58
61
|
homepage: https://github.com/sonots/memprof2
|
59
62
|
licenses:
|
60
63
|
- MIT
|
@@ -79,4 +82,6 @@ rubygems_version: 2.2.2
|
|
79
82
|
signing_key:
|
80
83
|
specification_version: 4
|
81
84
|
summary: Ruby memory profiler for >= Ruby 2.1.0
|
82
|
-
test_files:
|
85
|
+
test_files:
|
86
|
+
- test/helper.rb
|
87
|
+
- test/test_memprof2.rb
|