process-metrics 0.4.0 → 0.5.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: 42d11b0f2e725706c447c1b4cfa3f15a961f759fb8cacf0ef0d238338c3be6ab
4
- data.tar.gz: 80468efcb1b3eab151f8fcf0d054d93d11dcd90127ec70a6ad63e5fc10b68f89
3
+ metadata.gz: cbfff6ee5c7b2f09e1872bfaf86b520d999c94295de8d2328140ffeb84baa228
4
+ data.tar.gz: 2318ca3ac6a699863015b0f4ac32d22ee8845466f7046feee0155e89b9c5c5a8
5
5
  SHA512:
6
- metadata.gz: 5c765d57991e1a15e8c966ea1497234dae6e8e98cdd8e2463cefe1caf046770b1930b01b68b202b7ace9d802ad6d0577dfbb3cfef48a1d23abc3013ea5a48580
7
- data.tar.gz: 8c2bf4692a659037dc8167ad7f3349beb300e4bf021ee97b8ed3bf645cc83eaeefa19ae6ef5aee62855d781f7782ab9750d3999ca21982b865c24afbb65a0be5
6
+ metadata.gz: b4a69c2cc8a4055fcb9cd3612459b4e1a1164b8a4ac4095dafc8e7b51126915c79673b6023bc09f87357d69ac0aaf71e0caae9c2d3dd6a4fd3a7f8482d368b00
7
+ data.tar.gz: 17363223b2c6858e5f2e0241267e6dbaf6e97f58631483ef95af6fd7ad349d59915a8e486a27011a259c64f290f4da8ced1ea96e47bb3d0eb193c877ffdf2591
checksums.yaml.gz.sig CHANGED
Binary file
@@ -44,6 +44,8 @@ module Process
44
44
  options do
45
45
  option "--pid <integer>", "Report on a single process id.", type: Integer, required: true
46
46
  option "-p/--ppid <integer>", "Report on all children of this process id.", type: Integer, required: true
47
+
48
+ option "--total-memory <integer>", "Set the total memory relative to the usage (MiB).", type: Integer
47
49
  end
48
50
 
49
51
  def terminal
@@ -87,7 +89,7 @@ module Process
87
89
  return "#{value.round(unit)}#{units[unit]}"
88
90
  end
89
91
 
90
- def format_memory_usage(value, total, terminal)
92
+ def format_memory(value, total, terminal)
91
93
  if value > (total * 0.8)
92
94
  intensity = :high
93
95
  elsif value > (total * 0.5)
@@ -101,23 +103,23 @@ module Process
101
103
  terminal.print(formatted, intensity, "[", Bar.format(value / total.to_f, 60), "]", :reset)
102
104
  end
103
105
 
106
+ def total_memory
107
+ if total_memory = @options[:total_memory]
108
+ return total_memory * 1024
109
+ else
110
+ return Process::Metrics::Memory.total_size
111
+ end
112
+ end
113
+
104
114
  def call
105
115
  terminal = self.terminal
106
116
 
107
117
  summary = Process::Metrics::General.capture(pid: @options[:pid], ppid: @options[:ppid])
108
118
 
109
- format_memory_usage = self.method(:format_memory_usage).curry
110
- shared_memory_usage = 0
111
- private_memory_usage = 0
112
- total_memory_usage = 0
113
-
114
- summary.each do |pid, general|
115
- if memory = general.memory
116
- total_memory_usage += memory.proportional_size + memory.unique_size
117
- else
118
- total_memory_usage += general.resident_size
119
- end
120
- end
119
+ format_memory = self.method(:format_memory).curry
120
+ shared_memory = 0
121
+ private_memory = 0
122
+ total_memory = self.total_memory
121
123
 
122
124
  proportional = true
123
125
 
@@ -129,25 +131,25 @@ module Process
129
131
  terminal.print_line
130
132
 
131
133
  if memory = general.memory
132
- shared_memory_usage += memory.proportional_size
133
- private_memory_usage += memory.unique_size
134
+ shared_memory += memory.proportional_size
135
+ private_memory += memory.unique_size
134
136
 
135
137
  terminal.print_line(
136
- :key, "Shared Memory: ".rjust(20), :reset,
137
- format_memory_usage[memory.proportional_size, total_memory_usage]
138
+ :key, "Memory: ".rjust(20), :reset,
139
+ format_memory[memory.proportional_size, total_memory]
138
140
  )
139
141
 
140
142
  terminal.print_line(
141
143
  :key, "Private Memory: ".rjust(20), :reset,
142
- format_memory_usage[memory.unique_size, total_memory_usage]
144
+ format_memory[memory.unique_size, total_memory]
143
145
  )
144
146
  else
145
- shared_memory_usage += general.resident_size
147
+ shared_memory += general.resident_size
146
148
  proportional = false
147
149
 
148
150
  terminal.print_line(
149
151
  :key, "Memory: ".rjust(20), :reset,
150
- format_memory_usage[general.resident_size, total_memory_usage]
152
+ format_memory[general.resident_size, total_memory]
151
153
  )
152
154
  end
153
155
  end
@@ -156,24 +158,24 @@ module Process
156
158
 
157
159
  if proportional
158
160
  terminal.print_line(
159
- :key, "Shared Memory: ".rjust(20), :reset,
160
- format_memory_usage[shared_memory_usage, total_memory_usage]
161
+ :key, "Memory: ".rjust(20), :reset,
162
+ format_memory[shared_memory, total_memory]
161
163
  )
162
164
 
163
165
  terminal.print_line(
164
166
  :key, "Private Memory: ".rjust(20), :reset,
165
- format_memory_usage[private_memory_usage, total_memory_usage]
167
+ format_memory[private_memory, total_memory]
166
168
  )
167
169
  else
168
170
  terminal.print_line(
169
171
  :key, "Memory: ".rjust(20), :reset,
170
- format_memory_usage[memory_usage, total_memory_usage]
172
+ format_memory[memory, total_memory]
171
173
  )
172
174
  end
173
175
 
174
176
  terminal.print_line(
175
177
  :key, "Memory (Total): ".rjust(20), :reset,
176
- format_memory_usage[shared_memory_usage + private_memory_usage, total_memory_usage]
178
+ format_memory[shared_memory + private_memory, total_memory]
177
179
  )
178
180
  end
179
181
  end
@@ -113,8 +113,10 @@ module Process
113
113
  end
114
114
 
115
115
  def self.capture_memory(processes)
116
+ count = processes.size
117
+
116
118
  processes.each do |pid, process|
117
- process.memory = Memory.capture(Array(pid))
119
+ process.memory = Memory.capture(pid, count: count)
118
120
  end
119
121
  end
120
122
 
@@ -13,6 +13,18 @@ module Process
13
13
  File.executable?(VMMAP)
14
14
  end
15
15
 
16
+ # @returns [Numeric] Total memory size in kilobytes.
17
+ def self.total_size
18
+ # sysctl hw.memsize
19
+ IO.popen(["sysctl", "hw.memsize"], "r") do |io|
20
+ io.each_line do |line|
21
+ if line =~ /hw.memsize: (\d+)/
22
+ return $1.to_i / 1024
23
+ end
24
+ end
25
+ end
26
+ end
27
+
16
28
  # Parse a size string into kilobytes.
17
29
  def self.parse_size(string)
18
30
  return 0 unless string
@@ -35,51 +47,45 @@ module Process
35
47
  /x
36
48
 
37
49
  # Capture memory usage for the given process IDs.
38
- def self.capture(pids)
50
+ def self.capture(pid, count: 1, **options)
39
51
  usage = Memory.zero
40
52
 
41
- pids.each do |pid|
42
- IO.popen(["vmmap", pid.to_s], "r") do |io|
43
- io.each_line do |line|
44
- if match = LINE.match(line)
45
- virtual_size = parse_size(match[:virtual_size])
46
- resident_size = parse_size(match[:resident_size])
47
- dirty_size = parse_size(match[:dirty_size])
48
- swap_size = parse_size(match[:swap_size])
49
-
50
- # puts [match[:region_name], virtual_size, resident_size, dirty_size, swap_size, match[:permissions], match[:sharing_mode]].join(",")
51
-
52
- # Update counts
53
- usage.map_count += 1
54
- usage.resident_size += resident_size
55
- usage.swap_size += swap_size
56
-
57
- # Private vs. Shared memory
58
- # COW=copy_on_write PRV=private NUL=empty ALI=aliased
59
- # SHM=shared ZER=zero_filled S/A=shared_alias
60
- case match[:sharing_mode]
61
- when "PRV"
62
- usage.private_clean_size += resident_size - dirty_size
63
- usage.private_dirty_size += dirty_size
64
- when "COW", "SHM"
65
- usage.shared_clean_size += resident_size - dirty_size
66
- usage.shared_dirty_size += dirty_size
67
- end
68
-
69
- # Anonymous memory: no region detail path or special names
70
- if match[:region_name] =~ /MALLOC|VM_ALLOCATE|Stack|STACK|anonymous/
71
- usage.anonymous_size += resident_size
72
- end
73
- # else
74
- # puts "Failed to match line: #{line}"
53
+ IO.popen(["vmmap", pid.to_s], "r") do |io|
54
+ io.each_line do |line|
55
+ if match = LINE.match(line)
56
+ virtual_size = parse_size(match[:virtual_size])
57
+ resident_size = parse_size(match[:resident_size])
58
+ dirty_size = parse_size(match[:dirty_size])
59
+ swap_size = parse_size(match[:swap_size])
60
+
61
+ # Update counts
62
+ usage.map_count += 1
63
+ usage.resident_size += resident_size
64
+ usage.swap_size += swap_size
65
+
66
+ # Private vs. Shared memory
67
+ # COW=copy_on_write PRV=private NUL=empty ALI=aliased
68
+ # SHM=shared ZER=zero_filled S/A=shared_alias
69
+ case match[:sharing_mode]
70
+ when "PRV"
71
+ usage.private_clean_size += resident_size - dirty_size
72
+ usage.private_dirty_size += dirty_size
73
+ when "COW", "SHM"
74
+ usage.shared_clean_size += resident_size - dirty_size
75
+ usage.shared_dirty_size += dirty_size
76
+ end
77
+
78
+ # Anonymous memory: no region detail path or special names
79
+ if match[:region_name] =~ /MALLOC|VM_ALLOCATE|Stack|STACK|anonymous/
80
+ usage.anonymous_size += resident_size
75
81
  end
76
82
  end
77
83
  end
78
84
  end
79
85
 
80
- # On Darwin, we cannot compute the proportional size, so we just set it to the resident size.
81
- usage.proportional_size = usage.resident_size
82
- usage.proportional_swap_size = usage.swap_size
86
+ # Darwin does not expose proportional memory usage, so we guess based on the number of processes. Yes, this is a terrible hack, but it's the most reasonable thing to do given the constraints:
87
+ usage.proportional_size = usage.resident_size / count
88
+ usage.proportional_swap_size = usage.swap_size / count
83
89
 
84
90
  return usage
85
91
  end
@@ -91,8 +97,12 @@ module Process
91
97
  return true
92
98
  end
93
99
 
94
- def capture(pids)
95
- return Memory::Darwin.capture(pids)
100
+ def total_size
101
+ return Memory::Darwin.total_size
102
+ end
103
+
104
+ def capture(...)
105
+ return Memory::Darwin.capture(...)
96
106
  end
97
107
  end
98
108
  end
@@ -6,6 +6,15 @@
6
6
  module Process
7
7
  module Metrics
8
8
  class Memory::Linux
9
+ # @returns [Numeric] Total memory size in kilobytes.
10
+ def self.total_size
11
+ File.read("/proc/meminfo").each_line do |line|
12
+ if /MemTotal:\s+(?<total>\d+) kB/ =~ line
13
+ return total.to_i
14
+ end
15
+ end
16
+ end
17
+
9
18
  # The fields that will be extracted from the `smaps` data.
10
19
  SMAP = {
11
20
  "Rss" => :resident_size,
@@ -53,10 +62,10 @@ module Process
53
62
  end
54
63
 
55
64
  # Capture memory usage for the given process IDs.
56
- def self.capture(pids)
65
+ def self.capture(pid, **options)
57
66
  usage = Memory.zero
58
67
 
59
- pids.each do |pid|
68
+ begin
60
69
  File.foreach("/proc/#{pid}/smaps") do |line|
61
70
  # The format of this is fixed according to:
62
71
  # https://github.com/torvalds/linux/blob/351c8a09b00b5c51c8f58b016fffe51f87e2d820/fs/proc/task_mmu.c#L804-L814
@@ -89,8 +98,12 @@ module Process
89
98
  return true
90
99
  end
91
100
 
92
- def capture(pids)
93
- return Memory::Linux.capture(pids)
101
+ def total_size
102
+ return Memory::Linux.total_size
103
+ end
104
+
105
+ def capture(...)
106
+ return Memory::Linux.capture(...)
94
107
  end
95
108
  end
96
109
  end
@@ -37,7 +37,7 @@ module Process
37
37
  end
38
38
 
39
39
  # Capture memory usage for the given process IDs.
40
- def self.capture(pids)
40
+ def self.capture(pid, **options)
41
41
  return nil
42
42
  end
43
43
  end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Process
7
7
  module Metrics
8
- VERSION = "0.4.0"
8
+ VERSION = "0.5.0"
9
9
  end
10
10
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file