lib/process/metrics/memory.rb in process-metrics-0.2.1 vs lib/process/metrics/memory.rb in process-metrics-0.3.0
- old
+ new
@@ -1,88 +1,109 @@
# frozen_string_literal: true
-# Copyright, 2019, by Samuel G. D. Williams. <https://www.codeotaku.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
+# Released under the MIT License.
+# Copyright, 2019-2024, by Samuel Williams.
+require 'json'
+
module Process
module Metrics
- 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)
+ class Memory < Struct.new(:map_count, :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)
alias as_json to_h
+ # Convert the object to a JSON string.
def to_json(*arguments)
as_json.to_json(*arguments)
end
+ # The total size of the process in memory.
+ def total_size
+ self.resident_size + self.swap_size
+ end
+
# The unique set size, the size of completely private (unshared) data.
def unique_size
self.private_clean_size + self.private_dirty_size
end
- if File.readable?('/proc/self/smaps')
+ # The fields that will be extracted from the `smaps` data.
+ MAP = {
+ "Rss" => :resident_size,
+ "Pss" => :proportional_size,
+ "Shared_Clean" => :shared_clean_size,
+ "Shared_Dirty" => :shared_dirty_size,
+ "Private_Clean" => :private_clean_size,
+ "Private_Dirty" => :private_dirty_size,
+ "Referenced" => :referenced_size,
+ "Anonymous" => :anonymous_size,
+ "Swap" => :swap_size,
+ "SwapPss" => :proportional_swap_size,
+ }
+
+ if File.readable?('/proc/self/smaps_rollup')
+ # Whether the memory usage can be captured on this system.
def self.supported?
true
end
- MAP = {
- "Size" => :total_size,
- "Rss" => :resident_size,
- "Pss" => :proportional_size,
- "Shared_Clean" => :shared_clean_size,
- "Shared_Dirty" => :shared_dirty_size,
- "Private_Clean" => :private_clean_size,
- "Private_Dirty" => :private_dirty_size,
- "Referenced" => :referenced_size,
- "Anonymous" => :anonymous_size,
- "Swap" => :swap_size,
- "SwapPss" => :proportional_swap_size,
- }
+ # Capture memory usage for the given process IDs.
+ def self.capture(pids)
+ usage = self.new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+ pids.each do |pid|
+ File.foreach("/proc/#{pid}/smaps_rollup") do |line|
+ if /(?<name>.*?):\s+(?<value>\d+) kB/ =~ line
+ if key = MAP[name]
+ usage[key] += value.to_i
+ end
+ end
+ end
+
+ usage.map_count += File.readlines("/proc/#{pid}/maps").size
+ rescue Errno::ENOENT => error
+ # Ignore.
+ end
+
+ return usage
+ end
+ elsif File.readable?('/proc/self/smaps')
+ # Whether the memory usage can be captured on this system.
+ def self.supported?
+ true
+ end
+ # Capture memory usage for the given process IDs.
def self.capture(pids)
usage = self.new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
pids.each do |pid|
- if lines = File.readlines("/proc/#{pid}/smaps")
- lines.each do |line|
- # The format of this is fixed according to:
- # https://github.com/torvalds/linux/blob/351c8a09b00b5c51c8f58b016fffe51f87e2d820/fs/proc/task_mmu.c#L804-L814
- if /(?<name>.*?):\s+(?<value>\d+) kB/ =~ line
- if key = MAP[name]
- usage[key] += value.to_i
- end
- elsif /VmFlags:\s+(?<flags>.*)/ =~ line
- # It should be possible to extract the number of fibers and each fiber's memory usage.
- # flags = flags.split(/\s+/)
- usage.map_count += 1
+ File.foreach("/proc/#{pid}/smaps") do |line|
+ # The format of this is fixed according to:
+ # https://github.com/torvalds/linux/blob/351c8a09b00b5c51c8f58b016fffe51f87e2d820/fs/proc/task_mmu.c#L804-L814
+ if /(?<name>.*?):\s+(?<value>\d+) kB/ =~ line
+ if key = MAP[name]
+ usage[key] += value.to_i
end
+ elsif /VmFlags:\s+(?<flags>.*)/ =~ line
+ # It should be possible to extract the number of fibers and each fiber's memory usage.
+ # flags = flags.split(/\s+/)
+ usage.map_count += 1
end
end
+ rescue Errno::ENOENT => error
+ # Ignore.
end
return usage
end
else
+ # Whether the memory usage can be captured on this system.
def self.supported?
false
end
+ # Capture memory usage for the given process IDs.
def self.capture(pids)
return self.new
end
end
end