process-metrics 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -0
- data/bin/process-metrics +29 -0
- data/lib/process/metrics/command.rb +31 -0
- data/lib/process/metrics/command/summary.rb +177 -0
- data/lib/process/metrics/command/top.rb +53 -0
- data/lib/process/metrics/general.rb +102 -57
- data/lib/process/metrics/memory.rb +28 -15
- data/lib/process/metrics/version.rb +1 -1
- data/process-metrics.gemspec +2 -0
- metadata +22 -7
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7cec50409b679c3cb38ad2951f012f9ec80ebd932af96a27aa8e443724b6f08b
|
4
|
+
data.tar.gz: e93c274723c0a744b9b27d38f20e7ca7c430b33ad804d55f706d3ceda30b95b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c81cee9bea7a96472e8e649f6695fafeff89d6c129c0fbc967f4fecac94a5e52818225992d9cce94e75c43abbed8877c1a5da186f14aae3cc56d085c1651c2f2
|
7
|
+
data.tar.gz: 72694d4aa9dd22d9b9f3ec82bd66586119c1fc6be7edb278c5263279004b551c0a1d8b7364ab5877d503828d904aab9f58206d72fbec65b5d59ce518e01a36f3
|
data/README.md
CHANGED
@@ -133,6 +133,18 @@ pp metrics
|
|
133
133
|
# ... snip ...
|
134
134
|
```
|
135
135
|
|
136
|
+
### Metrics
|
137
|
+
|
138
|
+
On some platforms (currently only Linux), additional memory metrics are captured.
|
139
|
+
|
140
|
+
#### Proportional Set Size
|
141
|
+
|
142
|
+
The total private memory usage + shared memory usage divided by the number of processes sharing said data.
|
143
|
+
|
144
|
+
#### Unique Set Size
|
145
|
+
|
146
|
+
The total private memory usage.
|
147
|
+
|
136
148
|
## Contributing
|
137
149
|
|
138
150
|
1. Fork it
|
data/bin/process-metrics
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
14
|
+
# all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
# THE SOFTWARE.
|
23
|
+
|
24
|
+
require_relative '../lib/process/metrics/command'
|
25
|
+
|
26
|
+
begin
|
27
|
+
Process::Metrics::Command.call
|
28
|
+
rescue Interrupt
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'command/top'
|
22
|
+
|
23
|
+
module Process
|
24
|
+
module Metrics
|
25
|
+
module Command
|
26
|
+
def self.call(*arguments)
|
27
|
+
Top.call(*arguments)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'samovar'
|
22
|
+
|
23
|
+
require_relative '../general'
|
24
|
+
|
25
|
+
require 'console/terminal'
|
26
|
+
|
27
|
+
module Process
|
28
|
+
module Metrics
|
29
|
+
module Command
|
30
|
+
module Bar
|
31
|
+
BLOCK = [
|
32
|
+
" ",
|
33
|
+
"▏",
|
34
|
+
"▎",
|
35
|
+
"▍",
|
36
|
+
"▌",
|
37
|
+
"▋",
|
38
|
+
"▊",
|
39
|
+
"▉",
|
40
|
+
"█",
|
41
|
+
]
|
42
|
+
|
43
|
+
def self.format(value, width)
|
44
|
+
blocks = width * value
|
45
|
+
full_blocks = blocks.floor
|
46
|
+
partial_block = ((blocks - full_blocks) * BLOCK.size).floor
|
47
|
+
|
48
|
+
if partial_block.zero?
|
49
|
+
BLOCK.last * full_blocks
|
50
|
+
else
|
51
|
+
"#{BLOCK.last * full_blocks}#{BLOCK[partial_block]}"
|
52
|
+
end.ljust(width)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Summary < Samovar::Command
|
57
|
+
self.description = "Display a summary of memory usage statistics."
|
58
|
+
|
59
|
+
options do
|
60
|
+
option '--pid <integer>', "Report on a single process id.", type: Integer, required: true
|
61
|
+
option '-p/--ppid <integer>', "Report on all children of this process id.", type: Integer, required: true
|
62
|
+
|
63
|
+
option '--memory-scale <integer>', "Scale maximum memory usage to the specified amount (MiB).", type: Integer, default: 512
|
64
|
+
end
|
65
|
+
|
66
|
+
def terminal
|
67
|
+
terminal = Console::Terminal.for($stdout)
|
68
|
+
|
69
|
+
# terminal[:pid] = terminal.style(:blue)
|
70
|
+
terminal[:command] = terminal.style(nil, nil, :bold)
|
71
|
+
terminal[:key] = terminal.style(:cyan)
|
72
|
+
|
73
|
+
terminal[:low] = terminal.style(:green)
|
74
|
+
terminal[:medium] = terminal.style(:yellow)
|
75
|
+
terminal[:high] = terminal.style(:red)
|
76
|
+
|
77
|
+
return terminal
|
78
|
+
end
|
79
|
+
|
80
|
+
def format_pcpu(value, terminal)
|
81
|
+
if value > 80.0
|
82
|
+
intensity = :high
|
83
|
+
elsif value > 50.0
|
84
|
+
intensity = :medium
|
85
|
+
else
|
86
|
+
intensity = :low
|
87
|
+
end
|
88
|
+
|
89
|
+
formatted = "%5.1f%% " % value
|
90
|
+
|
91
|
+
terminal.print(formatted.rjust(10), intensity, "[", Bar.format(value / 100.0, 60), "]", :reset)
|
92
|
+
end
|
93
|
+
|
94
|
+
UNITS = ["KiB", "MiB", "GiB"]
|
95
|
+
|
96
|
+
def format_size(value, units: UNITS)
|
97
|
+
unit = 0
|
98
|
+
|
99
|
+
while value > 1024.0 && unit < units.size
|
100
|
+
value /= 1024.0
|
101
|
+
unit += 1
|
102
|
+
end
|
103
|
+
|
104
|
+
return "#{value.round(unit)}#{units[unit]}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def format_memory_usage(value, terminal, scale: @options[:memory_scale])
|
108
|
+
if value > (1024.0 * scale * 0.8)
|
109
|
+
intensity = :high
|
110
|
+
elsif value > (1024.0 * scale * 0.5)
|
111
|
+
intensity = :medium
|
112
|
+
else
|
113
|
+
intensity = :low
|
114
|
+
end
|
115
|
+
|
116
|
+
formatted = (format_size(value) + ' ').rjust(10)
|
117
|
+
|
118
|
+
terminal.print(formatted, intensity, "[", Bar.format(value / (1024.0 * scale), 60), "]", :reset)
|
119
|
+
end
|
120
|
+
|
121
|
+
def call
|
122
|
+
terminal = self.terminal
|
123
|
+
|
124
|
+
summary = Process::Metrics::General.capture(pid: @options[:pid], ppid: @options[:ppid])
|
125
|
+
|
126
|
+
format_memory_usage = self.method(:format_memory_usage).curry
|
127
|
+
memory_usage = 0
|
128
|
+
proportional = true
|
129
|
+
|
130
|
+
summary.each do |pid, general|
|
131
|
+
terminal.print_line(:pid, pid, :reset, " ", :command, general[:command])
|
132
|
+
|
133
|
+
terminal.print(:key, "Processor Usage: ".rjust(20), :reset)
|
134
|
+
format_pcpu(general.pcpu, terminal)
|
135
|
+
terminal.print_line
|
136
|
+
|
137
|
+
if memory = general.memory
|
138
|
+
memory_usage += memory.proportional_size
|
139
|
+
|
140
|
+
terminal.print_line(
|
141
|
+
:key, "Memory (PSS): ".rjust(20), :reset,
|
142
|
+
format_memory_usage[memory.proportional_size]
|
143
|
+
)
|
144
|
+
|
145
|
+
terminal.print_line(
|
146
|
+
:key, "Private (USS): ".rjust(20), :reset,
|
147
|
+
format_memory_usage[memory.unique_size]
|
148
|
+
)
|
149
|
+
else
|
150
|
+
memory_usage += general.rsz
|
151
|
+
proportional = false
|
152
|
+
|
153
|
+
terminal.print_line(
|
154
|
+
:key, "Memory (RSS): ".rjust(20), :reset,
|
155
|
+
format_memory_usage[general.rsz]
|
156
|
+
)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
terminal.print_line("Summary")
|
161
|
+
|
162
|
+
if proportional
|
163
|
+
terminal.print_line(
|
164
|
+
:key, "Memory (PSS): ".rjust(20), :reset,
|
165
|
+
format_memory_usage[memory_usage]
|
166
|
+
)
|
167
|
+
else
|
168
|
+
terminal.print_line(
|
169
|
+
:key, "Memory (RSS): ".rjust(20), :reset,
|
170
|
+
format_memory_usage[memory_usage]
|
171
|
+
)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'samovar'
|
22
|
+
|
23
|
+
require_relative 'summary'
|
24
|
+
require_relative '../version'
|
25
|
+
|
26
|
+
module Process
|
27
|
+
module Metrics
|
28
|
+
module Command
|
29
|
+
class Top < Samovar::Command
|
30
|
+
self.description = "Collect memory usage statistics."
|
31
|
+
|
32
|
+
options do
|
33
|
+
option '-h/--help', "Print out help information."
|
34
|
+
option '-v/--version', "Print out the application version."
|
35
|
+
end
|
36
|
+
|
37
|
+
nested :command, {
|
38
|
+
'summary' => Summary,
|
39
|
+
}, default: 'summary'
|
40
|
+
|
41
|
+
def call
|
42
|
+
if @options[:version]
|
43
|
+
puts "#{self.name} v#{VERSION}"
|
44
|
+
elsif @options[:help]
|
45
|
+
self.print_usage
|
46
|
+
else
|
47
|
+
@command.call
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -49,86 +49,131 @@ module Process
|
|
49
49
|
pcpu: ->(value){value.to_f},
|
50
50
|
time: self.method(:duration),
|
51
51
|
vsz: ->(value){value.to_i},
|
52
|
-
|
52
|
+
rsz: ->(value){value.to_i},
|
53
53
|
etime: self.method(:duration),
|
54
54
|
command: ->(value){value},
|
55
55
|
}
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
class General < Struct.new(:pid, :ppid, :pgid, :pcpu, :vsz, :rsz, :time, :etime, :command, :memory)
|
58
|
+
def as_json
|
59
|
+
{
|
60
|
+
pid: self.pid,
|
61
|
+
ppid: self.ppid,
|
62
|
+
pgid: self.pgid,
|
63
|
+
pcpu: self.pcpu,
|
64
|
+
vsz: self.vsz,
|
65
|
+
rsz: self.rsz,
|
66
|
+
time: self.time,
|
67
|
+
etime: self.etime,
|
68
|
+
command: self.command,
|
69
|
+
memory: self.memory&.as_json,
|
70
|
+
}
|
64
71
|
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.expand(pid, hierarchy, pids)
|
68
|
-
unless pids.include?(pid)
|
69
|
-
pids << pid
|
70
|
-
|
71
|
-
if children = hierarchy.fetch(pid, nil)
|
72
|
-
self.expand_children(children, hierarchy, pids)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.capture(pid: nil, ppid: nil, ps: PS, fields: FIELDS)
|
78
|
-
input, output = IO.pipe
|
79
72
|
|
80
|
-
arguments
|
81
|
-
|
82
|
-
if pid && ppid.nil?
|
83
|
-
arguments.push("-p", Array(pid).join(','))
|
84
|
-
else
|
85
|
-
arguments.push("ax")
|
73
|
+
def to_json(*arguments)
|
74
|
+
as_json.to_json(*arguments)
|
86
75
|
end
|
87
76
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
77
|
+
def memory_usage
|
78
|
+
if self.memory
|
79
|
+
self.memory.proportional_size
|
80
|
+
else
|
81
|
+
self.rsz
|
82
|
+
end
|
83
|
+
end
|
93
84
|
|
94
|
-
|
85
|
+
def self.expand_children(children, hierarchy, pids)
|
86
|
+
children.each do |pid|
|
87
|
+
self.expand(pid, hierarchy, pids)
|
88
|
+
end
|
89
|
+
end
|
95
90
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
91
|
+
def self.expand(pid, hierarchy, pids)
|
92
|
+
unless pids.include?(pid)
|
93
|
+
pids << pid
|
94
|
+
|
95
|
+
if children = hierarchy.fetch(pid, nil)
|
96
|
+
self.expand_children(children, hierarchy, pids)
|
97
|
+
end
|
98
|
+
end
|
101
99
|
end
|
102
100
|
|
103
|
-
|
104
|
-
pids = Set.new
|
101
|
+
def self.build_tree(processes)
|
105
102
|
hierarchy = Hash.new{|h,k| h[k] = []}
|
106
103
|
|
107
|
-
processes.
|
108
|
-
|
109
|
-
hierarchy[
|
104
|
+
processes.each_value do |process|
|
105
|
+
if ppid = process.ppid
|
106
|
+
hierarchy[ppid] << process.pid
|
110
107
|
end
|
111
108
|
end
|
112
109
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
110
|
+
return hierarchy
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.capture_memory(processes)
|
114
|
+
processes.each do |pid, process|
|
115
|
+
process.memory = Memory.capture(Array(pid))
|
118
116
|
end
|
119
117
|
end
|
120
118
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
119
|
+
def self.capture(pid: nil, ppid: nil, ps: PS, fields: FIELDS)
|
120
|
+
input, output = IO.pipe
|
121
|
+
|
122
|
+
arguments = [ps]
|
123
|
+
|
124
|
+
if pid && ppid.nil?
|
125
|
+
arguments.push("-p", Array(pid).join(','))
|
126
|
+
else
|
127
|
+
arguments.push("ax")
|
128
|
+
end
|
129
|
+
|
130
|
+
arguments.push("-o", fields.keys.join(','))
|
131
|
+
|
132
|
+
ps_pid = Process.spawn(*arguments, out: output, pgroup: true)
|
133
|
+
|
134
|
+
output.close
|
135
|
+
|
136
|
+
header, *lines = input.readlines.map(&:strip)
|
137
|
+
|
138
|
+
processes = {}
|
139
|
+
|
140
|
+
lines.map do |line|
|
141
|
+
record = fields.
|
142
|
+
zip(line.split(/\s+/, fields.size)).
|
143
|
+
map{|(key, type), value| type.call(value)}
|
144
|
+
|
145
|
+
instance = self.new(*record)
|
146
|
+
|
147
|
+
processes[instance.pid] = instance
|
148
|
+
end
|
149
|
+
|
150
|
+
if ppid
|
151
|
+
pids = Set.new
|
152
|
+
|
153
|
+
hierarchy = self.build_tree(processes)
|
154
|
+
|
155
|
+
self.expand_children(Array(pid), hierarchy, pids)
|
156
|
+
self.expand_children(Array(ppid), hierarchy, pids)
|
157
|
+
|
158
|
+
processes.select! do |pid, process|
|
159
|
+
if pid != ps_pid
|
160
|
+
pids.include?(pid)
|
161
|
+
end
|
125
162
|
end
|
126
163
|
end
|
164
|
+
|
165
|
+
if Memory.supported?
|
166
|
+
self.capture_memory(processes)
|
167
|
+
|
168
|
+
# if pid
|
169
|
+
# self.compute_summary(pid, processes)
|
170
|
+
# end
|
171
|
+
end
|
172
|
+
|
173
|
+
return processes
|
174
|
+
ensure
|
175
|
+
Process.wait(ps_pid) if ps_pid
|
127
176
|
end
|
128
|
-
|
129
|
-
return processes
|
130
|
-
ensure
|
131
|
-
Process.wait(ps_pid) if ps_pid
|
132
177
|
end
|
133
178
|
end
|
134
179
|
end
|
@@ -22,28 +22,40 @@
|
|
22
22
|
|
23
23
|
module Process
|
24
24
|
module Metrics
|
25
|
-
|
25
|
+
class Memory < Struct.new(:map_count, :total_size, :resident_size, :proportional_size, :shared_clean_size, :shared_dirty_size, :private_clean_size, :private_dirty_size, :referenced_size, :anonymous_size, :swap_size, :proportional_swap_size)
|
26
|
+
|
27
|
+
alias as_json to_h
|
28
|
+
|
29
|
+
def to_json(*arguments)
|
30
|
+
as_json.to_json(*arguments)
|
31
|
+
end
|
32
|
+
|
33
|
+
# The unique set size, the size of completely private (unshared) data.
|
34
|
+
def unique_size
|
35
|
+
self.private_clean_size + self.private_dirty_size
|
36
|
+
end
|
37
|
+
|
26
38
|
if File.readable?('/proc/self/smaps')
|
27
39
|
def self.supported?
|
28
40
|
true
|
29
41
|
end
|
30
42
|
|
31
43
|
MAP = {
|
32
|
-
"Size" => :
|
33
|
-
"Rss" => :
|
34
|
-
"Pss" => :
|
35
|
-
"Shared_Clean" => :
|
36
|
-
"Shared_Dirty" => :
|
37
|
-
"Private_Clean" => :
|
38
|
-
"Private_Dirty" => :
|
39
|
-
"Referenced" => :
|
40
|
-
"Anonymous" => :
|
41
|
-
"Swap" => :
|
42
|
-
"SwapPss" => :
|
44
|
+
"Size" => :total_size,
|
45
|
+
"Rss" => :resident_size,
|
46
|
+
"Pss" => :proportional_size,
|
47
|
+
"Shared_Clean" => :shared_clean_size,
|
48
|
+
"Shared_Dirty" => :shared_dirty_size,
|
49
|
+
"Private_Clean" => :private_clean_size,
|
50
|
+
"Private_Dirty" => :private_dirty_size,
|
51
|
+
"Referenced" => :referenced_size,
|
52
|
+
"Anonymous" => :anonymous_size,
|
53
|
+
"Swap" => :swap_size,
|
54
|
+
"SwapPss" => :proportional_swap_size,
|
43
55
|
}
|
44
56
|
|
45
57
|
def self.capture(pids)
|
46
|
-
usage =
|
58
|
+
usage = self.new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
47
59
|
|
48
60
|
pids.each do |pid|
|
49
61
|
if lines = File.readlines("/proc/#{pid}/smaps")
|
@@ -57,13 +69,13 @@ module Process
|
|
57
69
|
elsif /VmFlags:\s+(?<flags>.*)/ =~ line
|
58
70
|
# It should be possible to extract the number of fibers and each fiber's memory usage.
|
59
71
|
# flags = flags.split(/\s+/)
|
60
|
-
usage
|
72
|
+
usage.map_count += 1
|
61
73
|
end
|
62
74
|
end
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
66
|
-
return usage
|
78
|
+
return usage
|
67
79
|
end
|
68
80
|
else
|
69
81
|
def self.supported?
|
@@ -71,6 +83,7 @@ module Process
|
|
71
83
|
end
|
72
84
|
|
73
85
|
def self.capture(pids)
|
86
|
+
return self.new
|
74
87
|
end
|
75
88
|
end
|
76
89
|
end
|
data/process-metrics.gemspec
CHANGED
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
+
spec.add_dependency "console", "~> 1.8"
|
27
|
+
|
26
28
|
spec.add_development_dependency "covered"
|
27
29
|
spec.add_development_dependency "bundler"
|
28
30
|
spec.add_development_dependency "rake", "~> 12.0"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: process-metrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: console
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: covered
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,8 +84,7 @@ description:
|
|
70
84
|
email:
|
71
85
|
- samuel.williams@oriontransfer.co.nz
|
72
86
|
executables:
|
73
|
-
-
|
74
|
-
- setup
|
87
|
+
- process-metrics
|
75
88
|
extensions: []
|
76
89
|
extra_rdoc_files: []
|
77
90
|
files:
|
@@ -81,9 +94,11 @@ files:
|
|
81
94
|
- Gemfile
|
82
95
|
- README.md
|
83
96
|
- Rakefile
|
84
|
-
- bin/
|
85
|
-
- bin/setup
|
97
|
+
- bin/process-metrics
|
86
98
|
- lib/process/metrics.rb
|
99
|
+
- lib/process/metrics/command.rb
|
100
|
+
- lib/process/metrics/command/summary.rb
|
101
|
+
- lib/process/metrics/command/top.rb
|
87
102
|
- lib/process/metrics/general.rb
|
88
103
|
- lib/process/metrics/memory.rb
|
89
104
|
- lib/process/metrics/version.rb
|
@@ -108,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
123
|
- !ruby/object:Gem::Version
|
109
124
|
version: '0'
|
110
125
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
126
|
+
rubygems_version: 3.1.2
|
112
127
|
signing_key:
|
113
128
|
specification_version: 4
|
114
129
|
summary: Provide detailed OS-specific process metrics.
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "process/metrics"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|