process-metrics 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42d11b0f2e725706c447c1b4cfa3f15a961f759fb8cacf0ef0d238338c3be6ab
4
- data.tar.gz: 80468efcb1b3eab151f8fcf0d054d93d11dcd90127ec70a6ad63e5fc10b68f89
3
+ metadata.gz: e289675208cb093fe76b4a7041534a8bb835be238a6fadae2aafb0c030c62c69
4
+ data.tar.gz: 499bb3b23d66671225a321ac7fd3e3a32bfdbf2a39bd44f976ff9cfbc89f953e
5
5
  SHA512:
6
- metadata.gz: 5c765d57991e1a15e8c966ea1497234dae6e8e98cdd8e2463cefe1caf046770b1930b01b68b202b7ace9d802ad6d0577dfbb3cfef48a1d23abc3013ea5a48580
7
- data.tar.gz: 8c2bf4692a659037dc8167ad7f3349beb300e4bf021ee97b8ed3bf645cc83eaeefa19ae6ef5aee62855d781f7782ab9750d3999ca21982b865c24afbb65a0be5
6
+ metadata.gz: caa4d0e83a16610d6160d1ed845ad9ad2ecc79fc19f7b89cdc7d1d8e26a634febec374c149ce5608239035985b55d1eb417c153e6dcf73c733642fdb552336e9
7
+ data.tar.gz: e3cb7f4fcb5ce25d6146f272d8ab4148542c56d2559b06dabe9ed1f630cb8580b79d08f8b50a39e5c19fa4ea59f9df62e2af9e93d7fae6995ae4e77eea64699a
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,
@@ -27,10 +36,10 @@ module Process
27
36
  end
28
37
 
29
38
  # Capture memory usage for the given process IDs.
30
- def self.capture(pids)
39
+ def self.capture(pid, **options)
31
40
  usage = Memory.zero
32
41
 
33
- pids.each do |pid|
42
+ begin
34
43
  File.foreach("/proc/#{pid}/smaps_rollup") do |line|
35
44
  if /(?<name>.*?):\s+(?<value>\d+) kB/ =~ line
36
45
  if key = SMAP[name]
@@ -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.1"
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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file