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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/process/metrics/command/summary.rb +27 -25
- data/lib/process/metrics/general.rb +3 -1
- data/lib/process/metrics/memory/darwin.rb +50 -40
- data/lib/process/metrics/memory/linux.rb +17 -4
- data/lib/process/metrics/memory.rb +1 -1
- data/lib/process/metrics/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +1 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbfff6ee5c7b2f09e1872bfaf86b520d999c94295de8d2328140ffeb84baa228
|
4
|
+
data.tar.gz: 2318ca3ac6a699863015b0f4ac32d22ee8845466f7046feee0155e89b9c5c5a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
133
|
-
|
134
|
+
shared_memory += memory.proportional_size
|
135
|
+
private_memory += memory.unique_size
|
134
136
|
|
135
137
|
terminal.print_line(
|
136
|
-
:key, "
|
137
|
-
|
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
|
-
|
144
|
+
format_memory[memory.unique_size, total_memory]
|
143
145
|
)
|
144
146
|
else
|
145
|
-
|
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
|
-
|
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, "
|
160
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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(
|
50
|
+
def self.capture(pid, count: 1, **options)
|
39
51
|
usage = Memory.zero
|
40
52
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
#
|
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
|
95
|
-
return Memory::Darwin.
|
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(
|
65
|
+
def self.capture(pid, **options)
|
57
66
|
usage = Memory.zero
|
58
67
|
|
59
|
-
|
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
|
93
|
-
return Memory::Linux.
|
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
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
Binary file
|