memory-profiler 1.0.2 → 1.1.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.
metadata CHANGED
@@ -1,58 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memory-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
5
- prerelease:
4
+ version: 1.1.0
6
5
  platform: ruby
7
6
  authors:
8
- - Matthew Kerwin
9
- autorequire:
7
+ - Samuel Williams
10
8
  bindir: bin
11
- cert_chain: []
12
- date: 2013-02-27 00:00:00.000000000 Z
9
+ cert_chain:
10
+ - |
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
13
+ ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
14
+ CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
15
+ MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
16
+ MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
17
+ bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
18
+ igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
19
+ 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
20
+ sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
21
+ e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
22
+ XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
23
+ RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
24
+ tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
25
+ zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
26
+ xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
27
+ BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
28
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
29
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
30
+ cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
31
+ xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
32
+ c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
33
+ 8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
34
+ JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
35
+ eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
36
+ Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
37
+ voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
38
+ -----END CERTIFICATE-----
39
+ date: 1980-01-02 00:00:00.000000000 Z
13
40
  dependencies: []
14
- description: A rudimentary memory profiler that uses pure in-VM techniques to analyse
15
- the object space and attempt to determine memory usage trends.
16
- email:
17
- - matthew@kerwin.net.au
18
41
  executables: []
19
- extensions: []
42
+ extensions:
43
+ - ext/extconf.rb
20
44
  extra_rdoc_files: []
21
45
  files:
22
- - lib/memory-profiler.rb
23
- - LICENSE
24
- - README
25
- - Gemfile.lock
26
- homepage: https://github.com/phluid61/memory-profiler-gem
46
+ - context/getting-started.md
47
+ - context/index.yaml
48
+ - ext/extconf.rb
49
+ - ext/memory/profiler/capture.c
50
+ - ext/memory/profiler/capture.h
51
+ - ext/memory/profiler/profiler.c
52
+ - lib/memory/profiler/call_tree.rb
53
+ - lib/memory/profiler/capture.rb
54
+ - lib/memory/profiler/sampler.rb
55
+ - lib/memory/profiler/version.rb
56
+ - lib/memory/tracker.rb
57
+ - license.md
58
+ - readme.md
59
+ - releases.md
60
+ homepage: https://github.com/socketry/memory-profiler
27
61
  licenses:
28
- - Apache License 2.0
29
- post_install_message:
30
- rdoc_options:
31
- - --title
32
- - Memory Profiler
33
- - --main
34
- - MemoryProfiler
35
- - --line-numbers
36
- - --tab-width
37
- - '2'
62
+ - MIT
63
+ metadata:
64
+ documentation_uri: https://socketry.github.io/memory-profiler/
65
+ source_code_uri: https://github.com/socketry/memory-profiler
66
+ rdoc_options: []
38
67
  require_paths:
39
68
  - lib
40
69
  required_ruby_version: !ruby/object:Gem::Requirement
41
- none: false
42
70
  requirements:
43
- - - ! '>='
71
+ - - ">="
44
72
  - !ruby/object:Gem::Version
45
- version: '0'
73
+ version: '3.2'
46
74
  required_rubygems_version: !ruby/object:Gem::Requirement
47
- none: false
48
75
  requirements:
49
- - - ! '>='
76
+ - - ">="
50
77
  - !ruby/object:Gem::Version
51
- version: 1.3.6
78
+ version: '0'
52
79
  requirements: []
53
- rubyforge_project: mem-prof-ruby
54
- rubygems_version: 1.8.11
55
- signing_key:
56
- specification_version: 3
57
- summary: A Ruby Memory Profiler
80
+ rubygems_version: 3.6.9
81
+ specification_version: 4
82
+ summary: Efficient memory allocation tracking with call path analysis.
58
83
  test_files: []
metadata.gz.sig ADDED
Binary file
data/Gemfile.lock DELETED
@@ -1,13 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- memory-profiler (1.0.2)
5
-
6
- GEM
7
- specs:
8
-
9
- PLATFORMS
10
- ruby
11
-
12
- DEPENDENCIES
13
- memory-profiler!
data/LICENSE DELETED
@@ -1,13 +0,0 @@
1
- Copyright 2011 Matthew Kerwin
2
-
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License.
5
- You may obtain a copy of at
6
-
7
- http://www.apache.org/licenses/LICENSE-2.0
8
-
9
- Unless required by applicable law or agreed to in writing, software
10
- distributed under the License is distributed on an "AS IS" BASES,
11
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- See the License for the specific language governing permissions and
13
- limitations under the License.
data/README DELETED
@@ -1,71 +0,0 @@
1
- A rudimentary Ruby memory profiler that uses pure in-VM techniques to
2
- analyse the object space and attempt to determine memory usage trends.
3
-
4
- * Takes instantaneous snapshots, and can be used to determine trends
5
- between subsequent instances.
6
- * Can also be used to detect memory leaks (obscure object references,
7
- etc.) in particular blocks or sections of code.
8
-
9
- Note that this uses pure Ruby code and techniques, without patches to
10
- the VM. As such it is trivial to install and use, but it doesn't have
11
- access to raw memory management/garbage collection data, so is forced
12
- to estimate, and it will affect performance noticeably.
13
-
14
- It has been tested with the following Ruby versions (ruby -v):
15
- * ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]
16
- * ruby 1.9.1p243 (2009-07-16 revision 24175) [i486-linux]
17
-
18
- This project was inspired by the similar Ruby memory profiler at
19
- http://code.google.com/p/ruby-memory-profiler/ , which was apparently
20
- released under a BSD (or BSD-style) license; but since no attribution
21
- details were included, I haven't copied them here anywhere.
22
-
23
- -------------------------------------------------------------------------
24
-
25
- The simplest way to use this utility is to copy the file:
26
- lib/memory-profiler.rb
27
- to your project somewhere, and include it directly.
28
-
29
- However the correct way is to build the gem, so that you can use it in
30
- all your projects.
31
-
32
- -------------------------------------------------------------------------
33
-
34
- To build the gem, using rake:
35
-
36
- rake install
37
- rake clean
38
-
39
- Then in your code:
40
-
41
- require 'rubygems'
42
- require 'memory-profiler'
43
-
44
- -------------------------------------------------------------------------
45
-
46
- Refer to RDoc documentation for more detail, but here's an example for
47
- using the utility in your Ruby program:
48
-
49
- # start the daemon, and let us know the file to which it reports
50
- puts MemoryProfiler.start_daemon( :limit=>5, :delay=>10, :marshall_size=>true, :sort_by=>:absdelta )
51
-
52
- 5.times do
53
- blah = Hash.new([])
54
-
55
- # compare memory space before and after executing a block of code
56
- rpt = MemoryProfiler.start( :limit=>10 ) do
57
- # some activities likely to create object references
58
- 100.times{ blah[1] << 'aaaaa' }
59
- 1000.times{ blah[2] << 'bbbbb' }
60
- end
61
-
62
- # display the report in a (slightly) readable form
63
- puts MemoryProfiler.format(rpt)
64
-
65
- sleep 7
66
- end
67
-
68
- # terminate the daemon
69
- MemoryProfiler.stop_daemon
70
-
71
- -------------------------------------------------------------------------
@@ -1,332 +0,0 @@
1
- #!/usr/bin/ruby --
2
- # vim: tabstop=2:softtabstop=2:shiftwidth=2:noexpandtab
3
- =begin
4
-
5
- Author: Matthew Kerwin <matthew@kerwin.net.au>
6
- Version: 1.0.2
7
- Date: 2011-09-27
8
-
9
-
10
- Copyright 2011 Matthew Kerwin.
11
-
12
- Licensed under the Apache License, Version 2.0 (the "License");
13
- you may not use this file except in compliance with the License.
14
- You may obtain a copy of the License at
15
-
16
- http://www.apache.org/licenses/LICENSE-2.0
17
-
18
- Unless required by applicable law or agreed to in writing, software
19
- distributed under the License is distributed on an "AS IS" BASIS,
20
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- See the License for the specific language governing permissions and
22
- limitations under the License.
23
-
24
- =end
25
-
26
- require 'sync'
27
-
28
- module MemoryProfiler
29
- DEFAULTS = {
30
- # general options
31
- :sort_by => :current,
32
- :only => [],
33
- :ignore => [],
34
- :limit => 20,
35
- :force_gc => false,
36
- # daemon options
37
- :delay => 60,
38
- :filename => nil,
39
- # ObjectSpaceAnalyser options
40
- :string_debug => false,
41
- :marshall_size => false,
42
- }
43
- @@daemon_thread = nil
44
- @@daemon_sync = Sync.new
45
-
46
- @@start_data = nil
47
- @@start_sync = Sync.new
48
-
49
- #
50
- # Begins an analysis thread that runs periodically, reporting to a text
51
- # file at: /tmp/memory_profiler-<pid>.log
52
- #
53
- # Returns the filename used.
54
- #
55
- # Options:
56
- # :delay => 60 # number of seconds between summaries
57
- # :filename => nil # override the generated default
58
- # See: #start for other options
59
- #
60
- def self.start_daemon(opt = {})
61
- opt = DEFAULTS.merge(opt)
62
- filename = opt[:filename] || "/tmp/memory_profiler-#{Process.pid}.log"
63
- @@daemon_sync.synchronize(:EX) do
64
- raise 'daemon process already running' if @@daemon_thread
65
- @@daemon_thread = Thread.new do
66
- prev = Hash.new(0)
67
- file = File.open(filename, 'w')
68
- loop do
69
- begin
70
- GC.start if opt[:force_gc]
71
- curr = ObjectSpaceAnalyser.analyse(opt)
72
- data = self._delta(curr, prev, opt)
73
-
74
- file.puts '-'*80
75
- file.puts Time.now.to_s
76
- data.each {|k,c,d| file.printf( "%5d %+5d %s\n", c, d, k.name ) }
77
-
78
- prev = curr
79
- GC.start if opt[:force_gc]
80
- rescue ::Exception => err
81
- $stderr.puts "** MemoryProfiler daemon error: #{err}", err.backtrace.map{|b| "\t#{b}" }
82
- end
83
- sleep opt[:delay]
84
- end #loop
85
- end #Thread.new
86
- end
87
- filename
88
- end
89
-
90
- #
91
- # Terminates the analysis thread started by #start_daemon
92
- #
93
- def self.stop_daemon
94
- @@daemon_sync.synchronize(:EX) do
95
- raise 'no daemon process running' unless @@daemon_thread
96
- @@daemon_thread.kill
97
- @@daemon_thread.join
98
- @@daemon_thread = nil
99
- end
100
- self
101
- end
102
-
103
- #
104
- # Generates an instantaneous report on the current Ruby ObjectSpace, saved to
105
- # a text file at: /tmp/memory_profiler-<pid>-<time>.log
106
- #
107
- # Returns the filename used.
108
- #
109
- # See: #start for valid/default options, except that :sort_by may
110
- # only have the value :current or :none when using #report
111
- #
112
- def self.report(opt = {})
113
- opt = DEFAULTS.merge(opt)
114
- GC.start if opt[:force_gc]
115
-
116
- data = ObjectSpaceAnalyser.analyse(opt)
117
-
118
- if opt[:sort_by] == :current
119
- data = data.to_a.sort_by{|k,v| -v }
120
- data = data[0,opt[:limit]] if opt[:limit] > 0 and opt[:limit] < data.length
121
- elsif opt[:sort_by] != :none
122
- warn "MemoryProfiler: invalid option :sort_by => #{opt[:sort_by].inspect}; using :none"
123
- end
124
-
125
- filename = opt[:filename] || "/tmp/memory_profiler-#{Process.pid}-#{Time.now.to_i}.log"
126
- File.open(filename, 'w') do |f|
127
- data.each {|k,c| f.printf( "%5d %s\n", c, k.name ) }
128
- end
129
-
130
- GC.start if opt[:force_gc]
131
- filename
132
- end
133
-
134
- #
135
- # If a block is given, executes it and returns a summary. Otherwise,
136
- # starts the analyser, and waits for a call to #restart or #stop.
137
- #
138
- # Returned data is an array of:
139
- # [ [Class, current_usage, usage_delta], ... ]
140
- #
141
- # Options:
142
- # :sort_by => :current # how to order classes; :current | :delta | :absdelta | :none
143
- #
144
- # :only => [] # list of only classes to scan; if empty, scans all classes
145
- # :ignore => [] # list of classes to exclude from reports (including sub-classes and modules, but not namespaces)
146
- # :limit => 20 # how many of the top classes to report (less than 1 means 'all'); only matters if :sort_by is not :none
147
- #
148
- # :force_gc => true # if true, forces a garbage collection before and after generating report
149
- #
150
- # :string_debug => false # see ObjectSpaceAnalyser#analyse
151
- # :marshall_size => false # see ObjectSpaceAnalyser#analyse
152
- #
153
- def self.start(opt = {}, &block)
154
- opt = DEFAULTS.merge(opt)
155
- if block_given?
156
- # get pre-block analysis of ObjectSpace
157
- GC.start if opt[:force_gc]
158
- prev = ObjectSpaceAnalyser.analyse(opt)
159
- GC.start if opt[:force_gc]
160
-
161
- yield
162
-
163
- # get post-block analysis of ObjectSpace
164
- GC.start if opt[:force_gc]
165
- curr = ObjectSpaceAnalyser.analyse(opt)
166
-
167
- # calculate the differences before and after execution
168
- data = self._delta(curr, prev, opt)
169
-
170
- # return it
171
- GC.start if opt[:force_gc]
172
- data
173
- else
174
- @@start_sync.synchronize(:EX) do
175
- raise 'already started' if @@start_data
176
-
177
- GC.start if opt[:force_gc]
178
- @@start_data = [ObjectSpaceAnalyser.analyse(opt), opt]
179
- GC.start if opt[:force_gc]
180
- end
181
- self
182
- end
183
- end
184
-
185
- #
186
- # Stops the current analysis and emits the results.
187
- #
188
- # See: #start
189
- #
190
- def self.stop
191
- prev = nil
192
- opt = nil
193
- @@start_sync.synchronize(:EX) do
194
- raise 'not started' unless @@start_data
195
- prev, opt = @@start_data
196
- @@start_data = nil
197
- end
198
-
199
- # get the current state of affairs
200
- GC.start if opt[:force_gc]
201
- curr = ObjectSpaceAnalyser.analyse(opt)
202
-
203
- # calculate the differences before and after execution
204
- data = self._delta(curr, prev, opt)
205
-
206
- # return it
207
- GC.start if opt[:force_gc]
208
- data
209
- end
210
-
211
- #
212
- # Stops the current analysis, emits the results, and immediately starts
213
- # a new analysis.
214
- #
215
- # See: #stop, #start
216
- #
217
- def self.restart(opt = {})
218
- res = self.stop
219
- self.start(opt)
220
- res
221
- end
222
-
223
- # => [ [Class, current, delta], ... ]
224
- def self._delta(curr, prev, opt={}) #:nodoc:
225
- opt = DEFAULTS.merge(opt)
226
-
227
- # determine the difference between current and previous
228
- delta = Hash.new(0)
229
- (curr.keys + prev.keys).each do |k|
230
- delta[k] = curr[k] - prev[k]
231
- end
232
- data = delta.map{|k,d| [k, curr[k].to_i, d]}
233
-
234
- # organise data according to given options
235
- case opt[:sort_by]
236
- when :none
237
- opt[:limit] = -1
238
- when :current
239
- data = data.sort_by{|k,c,d| -( c ) }
240
- when :delta
241
- data = data.sort_by{|k,c,d| -( d ) }
242
- when :absdelta
243
- data = data.sort_by{|k,c,d| -( d.abs ) }
244
- else
245
- warn "MemoryProfiler: invalid option :sort_by => #{opt[:sort_by].inspect}; using :none"
246
- opt[:limit] = -1
247
- end
248
- data = data[0,opt[:limit]] if opt[:limit] > 0 and opt[:limit] < data.length
249
-
250
- # return it
251
- data
252
- end
253
-
254
- #
255
- # Formats data, such as that returned by #start , into a printable,
256
- # readable string.
257
- #
258
- def self.format(data)
259
- " Curr. Delta Class\n" +
260
- " ----- ----- -----\n" +
261
- data.map{|k,c,d| sprintf(" %5d %+5d %s\n", c, d, k.name) }.join
262
- end
263
-
264
-
265
- module ObjectSpaceAnalyser
266
- #
267
- # Returns a hash mapping each Class to its usage.
268
- #
269
- # If opt[:marshall_size] is true, the usage is estimated using Marshall.dump() for each instance;
270
- # otherwise it is a simple instance count.
271
- #
272
- # If opt[:string_debug] is true, the analyser writes a text file containing every string
273
- # in the Ruby ObjectSpace, at: /tmp/memory_profiler-<pid>-strings-<time>.log
274
- #
275
- # Uses opt[:only] and opt[:ignore] , as per MemoryProfiler#start
276
- #
277
- def self.analyse(opt = {})
278
- opt = MemoryProfiler::DEFAULTS.merge(opt)
279
- marshall_size = !!opt[:marshall_size]
280
- string_debug = !!opt[:string_debug]
281
- ign = opt[:ignore]
282
- only = opt[:only]
283
-
284
- res = Hash.new(0)
285
- str = [] if string_debug
286
- ObjectSpace.each_object do |o|
287
- if res[o.class] or ((only.empty? or only.any?{|y| o.is_a? y }) and ign.none?{|x| o.is_a? x })
288
- res[o.class] += (marshall_size ? self.__sizeof(o) : 1)
289
- end
290
- str.push o.inspect if string_debug and o.class == String
291
- end
292
- if string_debug
293
- self.__save str
294
- str = nil
295
- end
296
- res
297
- end
298
-
299
- # Estimates the size of an object using Marshall.dump()
300
- # Defaults to 1 if anything goes wrong.
301
- def self.__sizeof(o) #:nodoc:
302
- Marshall.dump(o).size
303
- rescue ::Exception
304
- 1
305
- end
306
-
307
- # a single place where the magic filename is defined
308
- def self.__save(str) #:nodoc:
309
- File.open("/tmp/memory_profiler-#{Process.pid}-strings-#{Time.now.to_i}.log", 'w') do |f|
310
- str.sort.each{|s| f.puts s }
311
- end
312
- str = nil
313
- end
314
- end
315
- end
316
-
317
-
318
- if $0 == __FILE__
319
- puts MemoryProfiler.start_daemon( :limit=>5, :delay=>10, :marshall_size=>true, :sort_by=>:absdelta )
320
-
321
- 5.times do
322
- blah = Hash.new([])
323
- rpt = MemoryProfiler.start( :limit=>10 ) do
324
- 100.times{ blah[1] << 'aaaaa' }
325
- 1000.times{ blah[2] << 'bbbbb' }
326
- end
327
- puts MemoryProfiler.format(rpt)
328
- sleep 7
329
- end
330
-
331
- MemoryProfiler.stop_daemon
332
- end