Skip to content

Commit c84197e

Browse files
All sizes in bytes.
1 parent 5c3b8e4 commit c84197e

10 files changed

Lines changed: 70 additions & 61 deletions

File tree

context/getting-started.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,24 @@ The {ruby Process::Metrics::General} struct contains the following fields:
6767
- `parent_process_id` - Parent Process ID, the process ID of the process that started this process.
6868
- `process_group_id` - Process Group ID, the process group ID of the process, which can be shared by multiple processes.
6969
- `processor_utilization` - Processor Utilization (%), the percentage of CPU time used by the process (over a system-specific duration).
70-
- `total_size` - Memory Size (KB), the total size of the process's memory space (usually over-estimated as it doesn't take into account shared memory).
71-
- `resident_size` - Resident (Set) Size (KB), the amount of physical memory used by the process.
70+
- `total_size` - Memory Size (bytes), the total size of the process's memory space (usually over-estimated as it doesn't take into account shared memory).
71+
- `resident_size` - Resident (Set) Size (bytes), the amount of physical memory used by the process.
7272
- `processor_time` - CPU Time (s), the amount of CPU time used by the process.
7373
- `elapsed_time` - Elapsed Time (s), the amount of time the process has been running.
7474
- `command` - Command Name, the name of the command that started the process.
7575

7676
The {ruby Process::Metrics::Memory} struct contains the following fields:
7777

7878
- `map_count` - Number of Memory Mappings, e.g. number of thread stacks, fiber stacks, shared libraries, memory mapped files, etc.
79-
- `resident_size` - Resident Memory Size (KB), the amount of physical memory used by the process.
80-
- `proportional_size` - Proportional Memory Size (KB), the amount of memory that the process is using, taking into account shared memory.
81-
- `shared_clean_size` - Shared Clean Memory Size (KB), the amount of shared memory that is clean (not modified).
82-
- `shared_dirty_size` - Shared Dirty Memory Size (KB), the amount of shared memory that is dirty (modified).
83-
- `private_clean_size` - Private Clean Memory Size (KB), the amount of private memory that is clean (not modified).
84-
- `private_dirty_size` - Private Dirty Memory Size (KB), the amount of private memory that is dirty (modified).
85-
- `referenced_size` - Referenced Memory Size (KB), active page-cache that isn't going to be reclaimed any time soon.
86-
- `anonymous_size` - Anonymous Memory Size (KB), mapped memory that isn't backed by a file.
87-
- `swap_size` - Swap Memory Size (KB), the amount of memory that has been swapped to disk.
88-
- `proportional_swap_size` - Proportional Swap Memory Size (KB), the amount of memory that has been swapped to disk, excluding shared memory.
79+
- `resident_size` - Resident Memory Size (bytes), the amount of physical memory used by the process.
80+
- `proportional_size` - Proportional Memory Size (bytes), the amount of memory that the process is using, taking into account shared memory.
81+
- `shared_clean_size` - Shared Clean Memory Size (bytes), the amount of shared memory that is clean (not modified).
82+
- `shared_dirty_size` - Shared Dirty Memory Size (bytes), the amount of shared memory that is dirty (modified).
83+
- `private_clean_size` - Private Clean Memory Size (bytes), the amount of private memory that is clean (not modified).
84+
- `private_dirty_size` - Private Dirty Memory Size (bytes), the amount of private memory that is dirty (modified).
85+
- `referenced_size` - Referenced Memory Size (bytes), active page-cache that isn't going to be reclaimed any time soon.
86+
- `anonymous_size` - Anonymous Memory Size (bytes), mapped memory that isn't backed by a file.
87+
- `swap_size` - Swap Memory Size (bytes), the amount of memory that has been swapped to disk.
88+
- `proportional_swap_size` - Proportional Swap Memory Size (bytes), the amount of memory that has been swapped to disk, excluding shared memory.
8989

9090
In general, the interpretation of these fields is operating system specific. At best, they provide a rough estimate of the process's memory usage, but you should consult the documentation for your operating system for more details on exactly what each field represents.

examples/cow.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@
5252

5353
minor = mem.minor_faults.to_i
5454
major = mem.major_faults.to_i
55-
unique = mem.unique_size.to_i # kB
55+
unique = mem.unique_size.to_i # bytes
5656

5757
delta_minor = last_minor ? (minor - last_minor) : 0
5858
delta_major = last_major ? (major - last_major) : 0
5959
delta_unique = last_unique ? (unique - last_unique) : 0
6060

61-
puts "[%2ds] minor: %d (+%d), major: %d (+%d), unique_kB: %d (+%d)" % [t, minor, delta_minor, major, delta_major, unique, delta_unique]
61+
puts "[%2ds] minor: %d (+%d), major: %d (+%d), unique_bytes: %d (+%d)" % [t, minor, delta_minor, major, delta_major, unique, delta_unique]
6262

6363
last_minor = minor
6464
last_major = major

guides/getting-started/readme.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,24 @@ The {ruby Process::Metrics::General} struct contains the following fields:
6767
- `parent_process_id` - Parent Process ID, the process ID of the process that started this process.
6868
- `process_group_id` - Process Group ID, the process group ID of the process, which can be shared by multiple processes.
6969
- `processor_utilization` - Processor Utilization (%), the percentage of CPU time used by the process (over a system-specific duration).
70-
- `total_size` - Memory Size (KB), the total size of the process's memory space (usually over-estimated as it doesn't take into account shared memory).
71-
- `resident_size` - Resident (Set) Size (KB), the amount of physical memory used by the process.
70+
- `total_size` - Memory Size (bytes), the total size of the process's memory space (usually over-estimated as it doesn't take into account shared memory).
71+
- `resident_size` - Resident (Set) Size (bytes), the amount of physical memory used by the process.
7272
- `processor_time` - CPU Time (s), the amount of CPU time used by the process.
7373
- `elapsed_time` - Elapsed Time (s), the amount of time the process has been running.
7474
- `command` - Command Name, the name of the command that started the process.
7575

7676
The {ruby Process::Metrics::Memory} struct contains the following fields:
7777

7878
- `map_count` - Number of Memory Mappings, e.g. number of thread stacks, fiber stacks, shared libraries, memory mapped files, etc.
79-
- `resident_size` - Resident Memory Size (KB), the amount of physical memory used by the process.
80-
- `proportional_size` - Proportional Memory Size (KB), the amount of memory that the process is using, taking into account shared memory.
81-
- `shared_clean_size` - Shared Clean Memory Size (KB), the amount of shared memory that is clean (not modified).
82-
- `shared_dirty_size` - Shared Dirty Memory Size (KB), the amount of shared memory that is dirty (modified).
83-
- `private_clean_size` - Private Clean Memory Size (KB), the amount of private memory that is clean (not modified).
84-
- `private_dirty_size` - Private Dirty Memory Size (KB), the amount of private memory that is dirty (modified).
85-
- `referenced_size` - Referenced Memory Size (KB), active page-cache that isn't going to be reclaimed any time soon.
86-
- `anonymous_size` - Anonymous Memory Size (KB), mapped memory that isn't backed by a file.
87-
- `swap_size` - Swap Memory Size (KB), the amount of memory that has been swapped to disk.
88-
- `proportional_swap_size` - Proportional Swap Memory Size (KB), the amount of memory that has been swapped to disk, excluding shared memory.
79+
- `resident_size` - Resident Memory Size (bytes), the amount of physical memory used by the process.
80+
- `proportional_size` - Proportional Memory Size (bytes), the amount of memory that the process is using, taking into account shared memory.
81+
- `shared_clean_size` - Shared Clean Memory Size (bytes), the amount of shared memory that is clean (not modified).
82+
- `shared_dirty_size` - Shared Dirty Memory Size (bytes), the amount of shared memory that is dirty (modified).
83+
- `private_clean_size` - Private Clean Memory Size (bytes), the amount of private memory that is clean (not modified).
84+
- `private_dirty_size` - Private Dirty Memory Size (bytes), the amount of private memory that is dirty (modified).
85+
- `referenced_size` - Referenced Memory Size (bytes), active page-cache that isn't going to be reclaimed any time soon.
86+
- `anonymous_size` - Anonymous Memory Size (bytes), mapped memory that isn't backed by a file.
87+
- `swap_size` - Swap Memory Size (bytes), the amount of memory that has been swapped to disk.
88+
- `proportional_swap_size` - Proportional Swap Memory Size (bytes), the amount of memory that has been swapped to disk, excluding shared memory.
8989

9090
In general, the interpretation of these fields is operating system specific. At best, they provide a rough estimate of the process's memory usage, but you should consult the documentation for your operating system for more details on exactly what each field represents.

lib/process/metrics/command/summary.rb

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,23 +90,28 @@ def format_processor_utilization(value, terminal)
9090
UNITS = ["KiB", "MiB", "GiB"]
9191

9292
# Format a memory size value in human-readable units.
93-
# @parameter value [Numeric] The size value in kilobytes.
93+
# @parameter value [Numeric] The size value in bytes.
9494
# @parameter units [Array(String)] The unit labels to use for scaling.
9595
# @returns [String] A formatted string with value and unit (e.g., "512KiB", "1.5MiB").
9696
def format_size(value, units: UNITS)
97-
unit = 0
97+
unit = -1
9898

99-
while value > 1024.0 && unit < units.size
99+
while value >= 1024.0 && unit < units.size - 1
100100
value /= 1024.0
101101
unit += 1
102102
end
103103

104-
return "#{value.round(unit)}#{units[unit]}"
104+
if unit < 0
105+
# Value is less than 1 KiB, show in bytes
106+
return "#{value.round(0)}B"
107+
else
108+
return "#{value.round(unit)}#{units[unit]}"
109+
end
105110
end
106111

107112
# Format a memory value with a horizontal bar showing utilization relative to total.
108-
# @parameter value [Numeric] The memory value in kilobytes.
109-
# @parameter total [Numeric] The total memory available in kilobytes.
113+
# @parameter value [Numeric] The memory value in bytes.
114+
# @parameter total [Numeric] The total memory available in bytes.
110115
# @parameter terminal [Console::Terminal] The terminal to output styled text.
111116
def format_memory(value, total, terminal)
112117
if value > (total * 0.8)
@@ -123,10 +128,11 @@ def format_memory(value, total, terminal)
123128
end
124129

125130
# Get the total memory to use for percentage calculations.
126-
# @returns [Integer] Total memory in kilobytes.
131+
# @returns [Integer] Total memory in bytes.
127132
def total_memory
128133
if total_memory = @options[:total_memory]
129-
return total_memory * 1024
134+
# Convert from MiB to bytes
135+
return total_memory * 1024 * 1024
130136
else
131137
return Process::Metrics::Memory.total_size
132138
end

lib/process/metrics/general.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ def self.duration(value)
4242
ppid: ->(value){value.to_i}, # Parent Process ID
4343
pgid: ->(value){value.to_i}, # Process Group ID
4444
pcpu: ->(value){value.to_f}, # Percentage CPU
45-
vsz: ->(value){value.to_i}, # Virtual Size (KiB)
46-
rss: ->(value){value.to_i}, # Resident Size (KiB)
45+
vsz: ->(value){value.to_i * 1024}, # Virtual Size (convert from KiB to bytes)
46+
rss: ->(value){value.to_i * 1024}, # Resident Size (convert from KiB to bytes)
4747
time: self.method(:duration), # CPU Time (seconds)
4848
etime: self.method(:duration), # Elapsed Time (seconds)
4949
command: ->(value){value}, # Command (name of the process)
@@ -73,7 +73,7 @@ def to_json(*arguments)
7373
as_json.to_json(*arguments)
7474
end
7575

76-
# The total size of the process in memory, in kilobytes.
76+
# The total size of the process in memory, in bytes.
7777
def total_size
7878
if memory = self.memory
7979
memory.proportional_size

lib/process/metrics/memory.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
module Process
99
module Metrics
10-
# Represents memory usage for a process, sizes are in kilobytes.
10+
# Represents memory usage for a process, sizes are in bytes.
1111
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, :minor_faults, :major_faults)
1212

1313
alias as_json to_h

lib/process/metrics/memory/darwin.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,29 @@ def self.supported?
1414
File.executable?(VMMAP)
1515
end
1616

17-
# @returns [Numeric] Total memory size in kilobytes.
17+
# @returns [Numeric] Total memory size in bytes.
1818
def self.total_size
1919
# sysctl hw.memsize
2020
IO.popen(["sysctl", "hw.memsize"], "r") do |io|
2121
io.each_line do |line|
2222
if line =~ /hw.memsize: (\d+)/
23-
return $1.to_i / 1024
23+
return $1.to_i
2424
end
2525
end
2626
end
2727
end
2828

29-
# Parse a size string from vmmap output into kilobytes.
29+
# Parse a size string from vmmap output into bytes.
3030
# @parameter string [String | Nil] The size string (e.g., "4K", "1.5M", "2G").
31-
# @returns [Integer] The size in kilobytes.
31+
# @returns [Integer] The size in bytes.
3232
def self.parse_size(string)
3333
return 0 unless string
3434

3535
case string.strip
36-
when /([\d\.]+)K/i then ($1.to_f).round
37-
when /([\d\.]+)M/i then ($1.to_f * 1024).round
38-
when /([\d\.]+)G/i then ($1.to_f * 1024 * 1024).round
39-
else (string.to_f / 1024).ceil
36+
when /([\d\.]+)K/i then ($1.to_f * 1024).round
37+
when /([\d\.]+)M/i then ($1.to_f * 1024 * 1024).round
38+
when /([\d\.]+)G/i then ($1.to_f * 1024 * 1024 * 1024).round
39+
else (string.to_f).ceil
4040
end
4141
end
4242

@@ -111,7 +111,7 @@ def supported?
111111
end
112112

113113
# Get total system memory size.
114-
# @returns [Integer] Total memory in kilobytes.
114+
# @returns [Integer] Total memory in bytes.
115115
def total_size
116116
return Memory::Darwin.total_size
117117
end

lib/process/metrics/memory/linux.rb

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ def self.capture_faults(pid, usage)
3737
# Ignore.
3838
end
3939

40-
# Determine the total memory size in kilobytes. This is the maximum amount of memory that can be used by the current process. If running in a container, this may be limited by the container runtime (e.g. cgroups).
40+
# Determine the total memory size in bytes. This is the maximum amount of memory that can be used by the current process. If running in a container, this may be limited by the container runtime (e.g. cgroups).
4141
#
42-
# @returns [Integer] The total memory size in kilobytes.
42+
# @returns [Integer] The total memory size in bytes.
4343
def self.total_size
4444
# Check for Kubernetes/cgroup memory limit first (cgroups v2):
4545
if File.exist?("/sys/fs/cgroup/memory.max")
4646
limit = File.read("/sys/fs/cgroup/memory.max").strip
4747
# "max" means unlimited, fall through to other methods:
4848
if limit != "max"
49-
return limit.to_i / 1024
49+
return limit.to_i
5050
end
5151
end
5252

@@ -55,15 +55,15 @@ def self.total_size
5555
limit = File.read("/sys/fs/cgroup/memory/memory.limit_in_bytes").strip.to_i
5656
# A very large number means unlimited, fall through:
5757
if limit > 0 && limit < CGROUP_V1_UNLIMITED_THRESHOLD
58-
return limit / 1024
58+
return limit
5959
end
6060
end
6161

6262
# Fall back to Linux system memory detection:
6363
if File.exist?("/proc/meminfo")
6464
File.foreach("/proc/meminfo") do |line|
6565
if /MemTotal:\s*(?<total>\d+)\s*kB/ =~ line
66-
return total.to_i
66+
return total.to_i * 1024
6767
end
6868
end
6969
end
@@ -100,7 +100,8 @@ def self.capture(pid, faults: true, **options)
100100
file.each_line do |line|
101101
if /(?<name>.*?):\s+(?<value>\d+) kB/ =~ line
102102
if key = SMAP[name]
103-
usage[key] += value.to_i
103+
# Convert from kilobytes to bytes
104+
usage[key] += value.to_i * 1024
104105
end
105106
end
106107
end
@@ -136,7 +137,8 @@ def self.capture(pid, faults: true, **options)
136137
# https://github.com/torvalds/linux/blob/351c8a09b00b5c51c8f58b016fffe51f87e2d820/fs/proc/task_mmu.c#L804-L814
137138
if /(?<name>.*?):\s+(?<value>\d+) kB/ =~ line
138139
if key = SMAP[name]
139-
usage[key] += value.to_i
140+
# Convert from kilobytes to bytes
141+
usage[key] += value.to_i * 1024
140142
end
141143
elsif /VmFlags:\s+(?<flags>.*)/ =~ line
142144
# It should be possible to extract the number of fibers and each fiber's memory usage.
@@ -170,7 +172,7 @@ def supported?
170172
end
171173

172174
# Get total system memory size.
173-
# @returns [Integer] Total memory in kilobytes.
175+
# @returns [Integer] Total memory in bytes.
174176
def total_size
175177
return Memory::Linux.total_size
176178
end

readme.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ Please see the [project documentation](https://socketry.github.io/process-metric
1616

1717
Please see the [project releases](https://socketry.github.io/process-metrics/releases/index) for all releases.
1818

19+
### Unreleased
20+
21+
- `Process::Metrics::Memory.total_size` takes into account cgroup limits.
22+
- On Linux, capturing faults is optional, controlled by `capture(faults: true/false)`.
23+
- Report all sizes in bytes for consistency.
24+
1925
### v0.7.0
2026

2127
- Be more proactive about returning nil if memory capture failed.
@@ -67,12 +73,6 @@ Please see the [project releases](https://socketry.github.io/process-metrics/rel
6773
- Implemented structured data using Ruby structs for better performance and clarity.
6874
- Added documentation about PSS (Proportional Set Size) and USS (Unique Set Size) metrics.
6975

70-
### v0.1.1
71-
72-
- Removed `Gemfile.lock` from version control.
73-
- Fixed process metrics to exclude the `ps` command itself from measurements.
74-
- Fixed documentation formatting issues.
75-
7676
## Contributing
7777

7878
We welcome contributions to this project.

releases.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- `Process::Metrics::Memory.total_size` takes into account cgroup limits.
66
- On Linux, capturing faults is optional, controlled by `capture(faults: true/false)`.
7+
- Report all sizes in bytes for consistency.
78

89
## v0.7.0
910

0 commit comments

Comments
 (0)