leak_profiler 0.2.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89876429b4752e3c46009f0c6237a6868c6ef0416e58c504680a4bf7e75773f7
4
- data.tar.gz: 6496e8a68442eefdf37b82f1e83e5040b259633e065420fc2d8f20e22596794a
3
+ metadata.gz: c65071dbbe8a5516095022d27fc86043512d1f2a1c12c8fcf24d9c3aea7e0a71
4
+ data.tar.gz: e2ba069b4a7b4ed7c369b72756ec8f97f2f32736ea212ae7092802d0e4aecf94
5
5
  SHA512:
6
- metadata.gz: 27aebb5b8a2e891b19ecf7d5f498efbfc309472f2bd33a40fdafdfec10fb7f5a87c1ee081c03fe5a4dcfc47c972e0c9c288a5ab2b2f554b68f3f32191c229068
7
- data.tar.gz: 22e1155055df5e750b1f0ac94a6ae0fdf5939402c14caa2ba0bfb43ff2bd10119025c28ccba3862817ad79a8e951cd55d9ad09a1fd54a6748da039a91217c2f6
6
+ metadata.gz: e3b875bd325d8ab5c36004b0c413ff7eeb742211e058669a5fd328dfe1ff654672b69a84cb4d627663085e37c0a540a881d36e40eb65c9a48e2b85fb23a99304
7
+ data.tar.gz: 6f26582f06e662a12ed60282fc41b78303de00ccd1350469e99565ec54ba142f1c68b966fea60e5294927aa724132165f9d49cdcdadba7ed2d30d478501c915f
data/README.md CHANGED
@@ -27,7 +27,7 @@ LeakProfiler.new.report.report_rss
27
27
  # ... your code that may have memory leaks ...
28
28
  ```
29
29
 
30
- ### `LeakProfiler#new`
30
+ ### `LeakProfiler.new`
31
31
  * Arguments:
32
32
  * `output_dir` (default `./leak_profiler`): Specify the output directory for report.
33
33
 
@@ -64,7 +64,8 @@ Referrers ----------------------------------------------------------------------
64
64
  * `interval` (default `30`): The interval in seconds for report.
65
65
  * `max_allocations` (default `10`): Outputs the specified number of objects that use a lot of memory.
66
66
  * `max_referrers` (default `3`): Outputs the number of references in order of the amount of memory used.
67
- * `report` (defalut `nil`): Specify the logger object if you want to use custom logger.
67
+ * `logger` (defalut `nil`): Specify the logger object if you want to use custom logger.
68
+ * `filename` (defalut `nil`): Specify the filename if you want to use custom filename.
68
69
 
69
70
  > [!WARNING]
70
71
  > This uses `ObjectSpace.allocation_sourcefile` method to measurement.
@@ -83,6 +84,7 @@ elapsed [sec],memory usage (rss) [MB]
83
84
 
84
85
  * Arguments:
85
86
  * `interval` (default `1`): The interval in seconds for report.
87
+ * `filename` (defalut `nil`): Specify the filename if you want to use custom filename.
86
88
 
87
89
  > [!WARNING]
88
90
  > This uses this uses `ps` command for measurement.
@@ -103,6 +105,7 @@ elapsed [sec],ObjectSpace.memsize_of_all values [MB]
103
105
 
104
106
  * Arguments:
105
107
  * `interval` (default `1`): The interval in seconds for report.
108
+ * `filename` (defalut `nil`): Specify the filename if you want to use custom filename.
106
109
 
107
110
  ## Contributing
108
111
 
data/Rakefile CHANGED
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
- require 'rubocop/rake_task'
4
+ require 'rake/testtask'
5
5
 
6
- RuboCop::RakeTask.new
6
+ task default: :test
7
7
 
8
- task default: :rubocop
8
+ Rake::TestTask.new do |task|
9
+ task.pattern = 'test/test_*.rb'
10
+ end
@@ -4,6 +4,8 @@ require 'objspace'
4
4
 
5
5
  class LeakProfiler
6
6
  class Allocations
7
+ attr_reader :thread
8
+
7
9
  def initialize(logger:, interval:, max_allocations:, max_referrers:)
8
10
  @logger = logger
9
11
  @interval = interval
@@ -12,7 +14,7 @@ class LeakProfiler
12
14
  end
13
15
 
14
16
  def report
15
- Thread.start do
17
+ @thread = Thread.start do
16
18
  loop do
17
19
  allocations = {}
18
20
 
@@ -9,26 +9,39 @@ require 'logger'
9
9
  class LeakProfiler
10
10
  def initialize(output_dir: './leak_profiler')
11
11
  @output_dir = output_dir
12
+ @threads = []
12
13
 
13
14
  FileUtils.mkdir_p(@output_dir)
14
15
  end
15
16
 
16
- def report(interval: 30, max_allocations: 10, max_referrers: 3, logger: nil)
17
- logger ||= Logger.new(File.join(@output_dir, "leak_profiler-#{Process.pid}.log"))
18
- LeakProfiler::Allocations.new(logger: logger, interval: interval, max_allocations: max_allocations, max_referrers: max_referrers).report
17
+ def report(interval: 30, max_allocations: 10, max_referrers: 3, logger: nil, filename: nil)
18
+ filename ||= "leak_profiler-#{Process.pid}.log"
19
+ logger ||= Logger.new(File.join(@output_dir, filename))
20
+ profiler = LeakProfiler::Allocations.new(logger: logger, interval: interval, max_allocations: max_allocations, max_referrers: max_referrers)
21
+ profiler.report
22
+ @threads << profiler.thread
19
23
 
20
24
  self
21
25
  end
22
26
 
23
- def report_rss(interval: 1)
24
- LeakProfiler::MemoryUsage.new(output_dir: @output_dir, interval: interval).report
27
+ def report_rss(interval: 1, filename: nil)
28
+ profiler = LeakProfiler::MemoryUsage.new(output_dir: @output_dir, interval: interval, filename: filename)
29
+ profiler.report
30
+ @threads << profiler.thread
25
31
 
26
32
  self
27
33
  end
28
34
 
29
- def report_memsize(interval: 1)
30
- LeakProfiler::MemoryMemsize.new(output_dir: @output_dir, interval: interval).report
35
+ def report_memsize(interval: 1, filename: nil)
36
+ profiler = LeakProfiler::MemoryMemsize.new(output_dir: @output_dir, interval: interval, filename: filename)
37
+ profiler.report
38
+ @threads << profiler.thread
31
39
 
32
40
  self
33
41
  end
42
+
43
+ def shutdown
44
+ @threads.each(&:kill)
45
+ @threads.each(&:join)
46
+ end
34
47
  end
@@ -4,23 +4,24 @@ require 'objspace'
4
4
 
5
5
  class LeakProfiler
6
6
  class MemoryMemsize
7
- def initialize(output_dir:, interval:)
7
+ attr_reader :thread
8
+
9
+ def initialize(output_dir:, interval:, filename: nil)
8
10
  @output_dir = output_dir
9
11
  @interval = interval
12
+ @filename = filename || "memory-memsize-#{Process.pid}.csv"
10
13
  end
11
14
 
12
15
  def report
13
- pid = Process.pid
14
-
15
- Thread.new do
16
+ @thread = Thread.start do
16
17
  i = 0
17
- File.open(File.expand_path(File.join(@output_dir, "memory-memsize-#{pid}.csv")), 'w') do |f|
18
+ File.open(File.expand_path(File.join(@output_dir, @filename)), 'w') do |f|
18
19
  f.puts('elapsed [sec],ObjectSpace.memsize_of_all values [MB]')
19
20
 
20
21
  loop do
21
22
  memsize = Float(ObjectSpace.memsize_of_all) / (1024 * 1024)
22
-
23
23
  f.puts("#{i},#{memsize}")
24
+ f.fsync
24
25
  i += @interval
25
26
  sleep(@interval)
26
27
  end
@@ -2,9 +2,12 @@
2
2
 
3
3
  class LeakProfiler
4
4
  class MemoryUsage
5
- def initialize(output_dir:, interval:)
5
+ attr_reader :thread
6
+
7
+ def initialize(output_dir:, interval:, filename: nil)
6
8
  @output_dir = output_dir
7
9
  @interval = interval
10
+ @filename = filename || "memory-usage-#{Process.pid}.csv"
8
11
  end
9
12
 
10
13
  def report
@@ -12,14 +15,15 @@ class LeakProfiler
12
15
 
13
16
  pid = Process.pid
14
17
 
15
- Thread.new do
18
+ @thread = Thread.start do
16
19
  i = 0
17
- File.open(File.expand_path(File.join(@output_dir, "memory-usage-#{pid}.csv")), 'w') do |f|
20
+ File.open(File.expand_path(File.join(@output_dir, @filename)), 'w') do |f|
18
21
  f.puts('elapsed [sec],memory usage (rss) [MB]')
19
22
 
20
23
  loop do
21
24
  rss = Integer(`ps -o rss= -p #{pid}`) / 1024.0
22
25
  f.puts("#{i},#{rss}")
26
+ f.fsync
23
27
  i += @interval
24
28
  sleep(@interval)
25
29
  end
@@ -2,9 +2,9 @@ class LeakProfiler
2
2
  def initialize: (?output_dir: String) -> void
3
3
 
4
4
  # TODO: Use valid type for logger
5
- def report: (?interval: Integer, ?max_allocations: Integer, ?max_referrers: Integer, ?logger: Object) -> self
5
+ def report: (?interval: Integer, ?max_allocations: Integer, ?max_referrers: Integer, ?logger: Object, ?filename: String) -> self
6
6
 
7
- def report_rss: (?interval: Integer) -> self
7
+ def report_rss: (?interval: Integer, ?filename: String) -> self
8
8
 
9
- def report_memsize: (?interval: Integer) -> self
9
+ def report_memsize: (?interval: Integer, ?filename: String) -> self
10
10
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'leak_profiler'
4
+ require 'minitest/autorun'
5
+
6
+ class LeakProfilerTest < Minitest::Test
7
+ def test_report
8
+ output_dir = './tmp'
9
+ profiler = LeakProfiler.new(output_dir: output_dir)
10
+
11
+ profiler.report(interval: 1, max_allocations: 5, max_referrers: 2, filename: 'test_report.log')
12
+ sleep(2)
13
+ profiler.shutdown
14
+
15
+ assert(File.exist?(File.join(output_dir, 'test_report.log')))
16
+ end
17
+
18
+ def test_report_rss
19
+ output_dir = './tmp'
20
+ profiler = LeakProfiler.new(output_dir: output_dir)
21
+
22
+ profiler.report_rss(interval: 1, filename: 'test_report_rss.csv')
23
+ sleep(2)
24
+ profiler.shutdown
25
+
26
+ assert(File.exist?(File.join(output_dir, 'test_report_rss.csv')))
27
+ end
28
+
29
+ def test_report_memsize
30
+ output_dir = './tmp'
31
+ profiler = LeakProfiler.new(output_dir: output_dir)
32
+
33
+ profiler.report_memsize(interval: 1, filename: 'test_report_memsize.csv')
34
+ sleep(2)
35
+ profiler.shutdown
36
+
37
+ assert(File.exist?(File.join(output_dir, 'test_report_memsize.csv')))
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leak_profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Watson
@@ -41,6 +41,7 @@ files:
41
41
  - lib/leak_profiler/memory_memsize.rb
42
42
  - lib/leak_profiler/memory_usage.rb
43
43
  - sig/leak_profiler.rbs
44
+ - test/test_leak_profiler.rb
44
45
  homepage: https://github.com/Watson1978/leak_profiler
45
46
  licenses:
46
47
  - MIT
@@ -62,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
63
  - !ruby/object:Gem::Version
63
64
  version: '0'
64
65
  requirements: []
65
- rubygems_version: 3.6.7
66
+ rubygems_version: 3.6.8
66
67
  specification_version: 4
67
68
  summary: A simple profiler for Ruby to detect memory leak.
68
69
  test_files: []