leak_profiler 0.5.1 → 0.7.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: b9eee59048d470d4ea437d6eabf4295b4b9fe98b547ed90f43675f56d31b30f4
4
- data.tar.gz: 3f85e846b9cb4e9e6232b69c2025e32223a410af5f8c1edf5a8903ebe24d97fd
3
+ metadata.gz: '0893023e2e636f17ea493dbb9e48a3663efdec4839aa0f8f92575fbf679d619f'
4
+ data.tar.gz: 5274e289f44e7d0157c337f44b02d8e7628b482d1c3033e22eee8d5a0b3addac
5
5
  SHA512:
6
- metadata.gz: e070418ef607471a5364579825addfcde2b1d4f13b882546f88cf24ceaea72754439f770d5c44a5c5e2500520ef579285ac9fa252271176295ab56a6074ec434
7
- data.tar.gz: 0be27cc605be614704a20976ec107f9dc56c63235cad4086123365c4f5b2b6ee74ad6cb55320f7cc868cd7661328348ec7797117afd8e018cc3c8a97cf45922f
6
+ metadata.gz: 565d9b09913c43416dce885ce9345e2d2d41a383c35d3238ff3d06609809da29b5e534ffaf6485069c850a9c7f9780f5a6b0221ec81345eb3d88724327bc0134
7
+ data.tar.gz: 762cc7effc4e9d7f0780fa193a60f6f977de4169d7a709d42cb5191e5fe88cc2be78b09603c0815a11774ff07b6888f8a5e75543f719a472cc3929f6ef7cfca7
data/README.md CHANGED
@@ -86,11 +86,6 @@ elapsed [sec],memory usage (rss) [MB]
86
86
  * `interval` (default `1`): The interval in seconds for report.
87
87
  * `filename` (defalut `nil`): Specify the filename if you want to use custom filename.
88
88
 
89
- > [!WARNING]
90
- > This uses this uses `ps` command for measurement.
91
- > So, this is not supported Windows platform.
92
-
93
-
94
89
  ### `LeakProfiler#report_memsize`
95
90
  This method outputs `ObjectSpace.memsize_of_all` values with CSV format, like:
96
91
 
@@ -1,38 +1,52 @@
1
1
  #include "ruby.h"
2
-
2
+ #include <stdio.h>
3
+ #include <unistd.h>
3
4
 
4
5
  // get the maximum resident set size (RSS) of the current process
5
6
  // return the value in kilobytes
6
7
  #if defined(_WIN32)
7
8
  #include <psapi.h>
8
9
 
9
- static VALUE leak_profiler_max_rss(VALUE self)
10
+ static VALUE leak_profiler_rss(VALUE self)
10
11
  {
11
- PROCESS_MEMORY_COUNTERS pmc;
12
+ PROCESS_MEMORY_COUNTERS pmc;
12
13
  if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
13
14
  rb_sys_fail("GetProcessMemoryInfo");
14
15
  }
15
16
  return LONG2NUM(pmc.PeakWorkingSetSize / 1024);
16
17
  }
17
18
 
18
- #else
19
- #include <sys/resource.h>
19
+ #elif defined(__APPLE__)
20
20
 
21
- static VALUE leak_profiler_max_rss(VALUE self)
22
- {
23
- struct rusage usage;
24
- long max_rss;
21
+ #include <mach/mach.h>
25
22
 
26
- if (getrusage(RUSAGE_SELF, &usage) == -1) {
27
- rb_sys_fail("getrusage");
23
+ static VALUE leak_profiler_rss(VALUE self)
24
+ {
25
+ struct mach_task_basic_info info;
26
+ mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
27
+ kern_return_t kr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count);
28
+ if (kr != KERN_SUCCESS) {
29
+ rb_sys_fail("task_info");
28
30
  }
29
- max_rss = usage.ru_maxrss;
31
+ return LONG2NUM(info.resident_size / 1024);
32
+ }
30
33
 
31
- #if defined(__APPLE__)
32
- max_rss = max_rss / 1024;
33
- #endif
34
+ #else // linux
34
35
 
35
- return LONG2NUM(max_rss);
36
+ static VALUE leak_profiler_rss(VALUE self)
37
+ {
38
+ long rss = 0;
39
+
40
+ FILE *file = fopen("/proc/self/statm", "r");
41
+ if (!file) {
42
+ rb_sys_fail("/proc/self/statm");
43
+ }
44
+ if (fscanf(file, "%*s%ld", &rss) != 1) {
45
+ fclose(file);
46
+ rb_sys_fail("fscanf");
47
+ }
48
+ fclose(file);
49
+ return LONG2NUM(rss * sysconf(_SC_PAGESIZE) / 1024);
36
50
  }
37
51
 
38
52
  #endif
@@ -43,5 +57,5 @@ void Init_leak_profiler_ext(void)
43
57
  VALUE cMemoryUsage = rb_define_class_under(cLeakProfiler, "MemoryUsage", rb_cObject);
44
58
 
45
59
 
46
- rb_define_singleton_method(cMemoryUsage, "max_rss", leak_profiler_max_rss, 0);
60
+ rb_define_singleton_method(cMemoryUsage, "rss", leak_profiler_rss, 0);
47
61
  }
@@ -22,13 +22,16 @@ class LeakProfiler
22
22
  def report
23
23
  @thread = Thread.start do
24
24
  loop do
25
- allocations = {}
26
-
27
25
  ObjectSpace.trace_object_allocations_start
28
26
  sleep(@interval)
29
27
  ObjectSpace.trace_object_allocations_stop
30
28
 
29
+ allocations = {}
30
+ allocations_by_class = Hash.new { |h, k| h[k] = 0 }
31
+
31
32
  ObjectSpace.each_object.each do |obj|
33
+ allocations_by_class[obj.class] += ObjectSpace.memsize_of(obj)
34
+
32
35
  key = allocated_location(obj)
33
36
  next unless key
34
37
 
@@ -40,6 +43,7 @@ class LeakProfiler
40
43
  allocations[key][:sample_object] = obj
41
44
  end
42
45
 
46
+ report_allocations_class(allocations_by_class)
43
47
  report_allocations(allocations)
44
48
  report_referrer_objects(allocations)
45
49
  end
@@ -48,6 +52,16 @@ class LeakProfiler
48
52
 
49
53
  private
50
54
 
55
+ def report_allocations_class(allocations_by_class)
56
+ return if @max_allocations <= 0
57
+
58
+ @logger.add(Logger::Severity::INFO, "Allocations by class #{"~" * 80}")
59
+ allocations_by_class.sort_by { |_, v| -v }
60
+ .take(@max_allocations).each do |klass, value|
61
+ @logger.add(Logger::Severity::INFO, "#{klass} retains #{value} bytes")
62
+ end
63
+ end
64
+
51
65
  def report_allocations(allocations)
52
66
  return if @max_allocations <= 0
53
67
 
@@ -22,7 +22,7 @@ class LeakProfiler
22
22
  f.puts('elapsed [sec],memory usage (rss) [MB]')
23
23
 
24
24
  loop do
25
- rss = LeakProfiler::MemoryUsage.max_rss / 1024.0
25
+ rss = LeakProfiler::MemoryUsage.rss / 1024.0
26
26
  f.puts("#{i},#{rss}")
27
27
  f.fsync
28
28
  i += @interval
@@ -14,6 +14,8 @@ class LeakProfiler
14
14
 
15
15
  private
16
16
 
17
+ def report_allocations_class: (untyped allocations_by_class) -> untyped
18
+
17
19
  def report_allocations: (untyped allocations) -> untyped
18
20
 
19
21
  def report_referrer_objects: (untyped allocations) -> untyped
@@ -1,5 +1,5 @@
1
1
  class LeakProfiler
2
2
  class MemoryUsage
3
- def self.max_rss: () -> Integer
3
+ def self.rss: () -> Integer
4
4
  end
5
5
  end
@@ -5,6 +5,6 @@ require 'minitest/autorun'
5
5
 
6
6
  class MemoryUsageTest < Minitest::Test
7
7
  def test_report_rss
8
- assert_equal(true, LeakProfiler::MemoryUsage.max_rss.positive?)
8
+ assert_equal(true, LeakProfiler::MemoryUsage.rss.positive?)
9
9
  end
10
10
  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.5.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Watson
@@ -71,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  - !ruby/object:Gem::Version
72
72
  version: '0'
73
73
  requirements: []
74
- rubygems_version: 3.6.7
74
+ rubygems_version: 3.6.9
75
75
  specification_version: 4
76
76
  summary: A simple profiler for Ruby to detect memory leak.
77
77
  test_files: []