process-metrics 0.4.0 → 0.5.0

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: 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