sys-memory 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 457079deac5b71c2aa7827dc99fd05ad3a2096937db1d59d0824fa9d19307fc3
4
- data.tar.gz: 8d3a0331639955099db7909cace2e596a5972573053ec88f4f7e9013051ae474
3
+ metadata.gz: 25b5f9d04be24191f9eb133c8cd851a39b8c46df7464d0dc9256dfbaf0d88f6d
4
+ data.tar.gz: 065dfcc2df8519394092d64cb4f354dd9c33e12cb9d982e1df861ea564c6410f
5
5
  SHA512:
6
- metadata.gz: 3e3c784ef9a72e5c8f1a1ed0a8de66355381fb8391744440c621346b965dc45d55276737a9d4417ec8057550bb561ed54285dbf1935b33abbfc723b89cdeaef1
7
- data.tar.gz: a8910b5ad70f11cea073144e08a9db16b876669ec2611bf75cb8e6624e6ac2d0c88dae07fe28f0ef387e1feca55c57d989dc5e042f79c351072a7137d107f36a
6
+ metadata.gz: aa249753e3a61d6d77a74fb3bfef92cbaeb440e78e0f6c37f11c708756713e5381fc1f6572a9ab2eb8d2392f00f67d63b04d53bfe662f1f987a19cc8674d1991
7
+ data.tar.gz: 46c66b080426c803617ba62579d570fda47b5a12d7e2f35270963e3e1709a12411044924498e1f435396c215c997401671e38bbe455fe5eef9837a73c569f905
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGES.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.3.0 - 3-Jun-2026
2
+ * Added an .available method. Thanks go to Splendide-Imaginarius for the
3
+ original inspiration.
4
+ * Fixed the MacOS version. Recent versions of MacOS added more vm_stat
5
+ struct members so that code was updated accordingly.
6
+ * Minor gemspec tweak.
7
+
1
8
  ## 0.2.1 - 2-Jun-2026
2
9
  * Fixed swap for FreeBSD.
3
10
  * Rubocop fixes.
data/README.md CHANGED
@@ -9,7 +9,7 @@ A Ruby interface for getting memory information.
9
9
  * OSX
10
10
  * BSD
11
11
 
12
- Note that only DragonflyBSD has been tested. I am not sure about other flavors yet.
12
+ Note that only FreeBSD and DragonflyBSD have been tested. I am not sure about other flavors yet.
13
13
 
14
14
  ## Installation
15
15
  `gem install sys-memory`
@@ -27,7 +27,7 @@ p Sys::Memory.total # Total memory, no swap
27
27
  p Sys::Memory.total(extended: true) # Total memory, include swap
28
28
  ```
29
29
 
30
- There's also the `free`, `used` and `load` module methods.
30
+ There's also the `free`, `available`, `used` and `load` module methods.
31
31
 
32
32
  ## Notes
33
33
  I realize there are some philosophical differences about what constitutes
@@ -35,6 +35,11 @@ I realize there are some philosophical differences about what constitutes
35
35
  it that I saw debated online. In short, you can choose to include swap memory
36
36
  as part of memory calculations or not as you see fit via an optional argument.
37
37
 
38
+ The `free` method reports memory the operating system currently classifies as
39
+ free. The `available` method reports memory that can be used by new work without
40
+ serious memory pressure. On platforms that expose caches or inactive pages
41
+ separately, `available` may be higher than `free`.
42
+
38
43
  You can also just use `Sys::Memory.memory` and collate the various hash data
39
44
  pieces as you see fit.
40
45
 
@@ -47,7 +52,7 @@ https://github.com/djberg96/sys-memory
47
52
  Apache-2.0
48
53
 
49
54
  ## Copyright
50
- (C) 2021-2024 Daniel J. Berger, All Rights Reserved
55
+ (C) 2021-2026 Daniel J. Berger, All Rights Reserved
51
56
 
52
57
  ## Warranty
53
58
  This package is provided "as is" and without any express or
@@ -62,6 +62,8 @@ module Sys
62
62
  hash[:swap_free] = hash[:swap_size] - get_by_name('vm.swap_reserved') # Best guess
63
63
  end
64
64
 
65
+ hash[:available] = hash[:free] + hash[:inactive] + hash[:cache]
66
+
65
67
  hash
66
68
  end
67
69
 
@@ -83,6 +85,18 @@ module Sys
83
85
  extended ? hash[:free] + hash[:swap_free] : hash[:free]
84
86
  end
85
87
 
88
+ # The memory currently available, in bytes. This includes free memory and
89
+ # inactive/cache pages that the system can reclaim.
90
+ # If the +extended+ option is set to true, then free swap memory is also
91
+ # included.
92
+ #
93
+ def available(extended: false)
94
+ hash = memory
95
+ available = hash[:available]
96
+
97
+ extended ? available + hash[:swap_free] : available
98
+ end
99
+
86
100
  # The memory, in bytes, currently in use. By default this is only
87
101
  # physical memory, but if the +extended+ option is set to true then
88
102
  # swap is included in the calculation.
@@ -99,7 +113,7 @@ module Sys
99
113
  (used(extended: extended) / total(extended: extended).to_f).round(2) * 100
100
114
  end
101
115
 
102
- module_function :memory, :total, :free, :load, :used
116
+ module_function :memory, :total, :free, :available, :load, :used
103
117
 
104
118
  private
105
119
 
@@ -44,6 +44,21 @@ module Sys
44
44
  extended ? (hash['MemFree'] + hash['SwapFree']) * 1024 : hash['MemFree'] * 1024
45
45
  end
46
46
 
47
+ # The memory currently available, in bytes. This is an estimate of the
48
+ # amount of memory available for starting new applications, without swapping.
49
+ # If the +extended+ option is set to true, then free swap memory is also
50
+ # included.
51
+ #
52
+ def available(extended: false)
53
+ hash = memory
54
+
55
+ available = hash.fetch('MemAvailable') do
56
+ hash['MemFree'] + hash['Buffers'] + hash['Cached'] + hash.fetch('SReclaimable', 0)
57
+ end
58
+
59
+ extended ? (available + hash['SwapFree']) * 1024 : available * 1024
60
+ end
61
+
47
62
  # The memory, in bytes, currently in use. By default this is only
48
63
  # physical memory, but if the +extended+ option is set to true then
49
64
  # swap is included in the calculation.
@@ -61,6 +76,6 @@ module Sys
61
76
  (used(extended: extended) / total(extended: extended).to_f).round(2) * 100
62
77
  end
63
78
 
64
- module_function :memory, :total, :free, :used, :load
79
+ module_function :memory, :total, :free, :available, :used, :load
65
80
  end # Memory
66
81
  end # Sys
@@ -11,10 +11,10 @@ module Sys
11
11
  ffi_lib FFI::Library::LIBC
12
12
 
13
13
  HOST_VM_INFO64 = 4
14
- HOST_VM_INFO64_COUNT = 38
14
+ INTEGER_T_SIZE = 4
15
15
 
16
16
  private_constant :HOST_VM_INFO64
17
- private_constant :HOST_VM_INFO64_COUNT
17
+ private_constant :INTEGER_T_SIZE
18
18
 
19
19
  attach_function :sysctlbyname, %i[string pointer pointer pointer size_t], :int
20
20
  attach_function :host_page_size, %i[pointer pointer], :int
@@ -65,7 +65,19 @@ module Sys
65
65
  :throttled_count, :natural_t, # of pages throttled
66
66
  :external_page_count, :natural_t, # of pages that are file-backed (non-swap)
67
67
  :internal_page_count, :natural_t, # of pages that are anonymous
68
- :total_uncompressed_pages_in_compressor, :uint64_t # of pages (uncompressed) held within the compressor
68
+ :total_uncompressed_pages_in_compressor, :uint64_t, # of pages (uncompressed) held within the compressor
69
+ :swapped_count, :uint64_t, # of compressor-stored pages currently stored in swap
70
+ :total_tag_storage_pages, :uint64_t,
71
+ :nontag_pageable_tag_storage_pages, :uint64_t,
72
+ :nontag_wired_tag_storage_pages, :uint64_t,
73
+ :free_tag_storage_pages, :uint64_t,
74
+ :tag_storing_tag_storage_pages, :uint64_t,
75
+ :total_tagged_pages, :uint64_t,
76
+ :resident_tagged_pages, :uint64_t,
77
+ :compressed_tagged_pages, :uint64_t,
78
+ :tagged_compressions, :uint64_t,
79
+ :tagged_decompressions, :uint64_t,
80
+ :compressed_tag_storage_bytes, :uint64_t
69
81
  )
70
82
  end
71
83
 
@@ -112,8 +124,8 @@ module Sys
112
124
 
113
125
  host_self = mach_host_self()
114
126
  vmstat = VmStat.new
115
- count = FFI::MemoryPointer.new(:size_t)
116
- count.write_int(vmstat.size)
127
+ count = FFI::MemoryPointer.new(:uint)
128
+ count.write_uint(vmstat.size / INTEGER_T_SIZE)
117
129
 
118
130
  rv = host_statistics64(host_self, HOST_VM_INFO64, vmstat, count)
119
131
  raise SystemCallError.new('host_statistics64', rv) if rv != 0
@@ -124,6 +136,7 @@ module Sys
124
136
  hash[:speculative] = vmstat[:speculative_count] * page_size
125
137
  hash[:wire] = vmstat[:wire_count] * page_size
126
138
  hash[:compressed] = vmstat[:compressor_page_count] * page_size
139
+ hash[:available] = hash[:free] + hash[:inactive]
127
140
 
128
141
  hash
129
142
  ensure
@@ -148,6 +161,18 @@ module Sys
148
161
  extended ? hash[:free] + hash[:swap_available] : hash[:free]
149
162
  end
150
163
 
164
+ # The memory currently available, in bytes. This includes free memory and
165
+ # inactive pages that the system can reclaim.
166
+ # If the +extended+ option is set to true, then available swap memory is
167
+ # also included.
168
+ #
169
+ def available(extended: false)
170
+ hash = memory
171
+ available = hash[:available]
172
+
173
+ extended ? available + hash[:swap_available] : available
174
+ end
175
+
151
176
  # The memory, in bytes, currently in use. By default this is only
152
177
  # physical memory, but if the +extended+ option is set to true then
153
178
  # swap is included in the calculation.
@@ -164,6 +189,6 @@ module Sys
164
189
  (used(extended: extended) / total(extended: extended).to_f).round(2) * 100
165
190
  end
166
191
 
167
- module_function :memory, :total, :free, :load, :used
192
+ module_function :memory, :total, :free, :available, :load, :used
168
193
  end
169
194
  end
data/lib/sys/version.rb CHANGED
@@ -3,6 +3,6 @@
3
3
  module Sys
4
4
  module Memory
5
5
  # The version of the sys-memory library.
6
- VERSION = '0.2.1'
6
+ VERSION = '0.3.0'
7
7
  end
8
8
  end
@@ -118,6 +118,18 @@ module Sys
118
118
  extended ? hash['AvailPhys'] + hash['AvailPageFile'] : hash['AvailPhys']
119
119
  end
120
120
 
121
+ # The physical memory currently available, in bytes. This is the amount of
122
+ # physical memory that can be immediately reused without having to write
123
+ # its contents to disk first.
124
+ #
125
+ # If the +extended+ option is set to true then available swap (pagefile)
126
+ # memory is included as part of the total.
127
+ #
128
+ def available(extended: false)
129
+ hash = memory
130
+ extended ? hash['AvailPhys'] + hash['AvailPageFile'] : hash['AvailPhys']
131
+ end
132
+
121
133
  # The memory, in bytes, currently in use. By default this is only
122
134
  # physical memory, but if the +extended+ option is set to true then
123
135
  # swap (pagefile) is included in the calculation.
@@ -136,6 +148,6 @@ module Sys
136
148
  memory['MemoryLoad']
137
149
  end
138
150
 
139
- module_function :memory, :total, :free, :load, :used
151
+ module_function :memory, :total, :free, :available, :load, :used
140
152
  end
141
153
  end
@@ -17,7 +17,7 @@ RSpec.describe Sys::Memory do
17
17
 
18
18
  context 'Sys::Memory::VERSION' do
19
19
  example 'the version constant is set to the expected value' do
20
- expect(described_class::VERSION).to eq('0.2.1')
20
+ expect(described_class::VERSION).to eq('0.3.0')
21
21
  expect(described_class::VERSION).to be_frozen
22
22
  end
23
23
  end
@@ -68,6 +68,20 @@ RSpec.describe Sys::Memory do
68
68
  end
69
69
  end
70
70
 
71
+ context 'Sys::Memory.available' do
72
+ example 'the available singleton method is defined' do
73
+ expect(described_class).to respond_to(:available)
74
+ end
75
+
76
+ example 'the available singleton method returns a sane value' do
77
+ expect(described_class.available).to be > 64.megabytes
78
+ end
79
+
80
+ example 'the available singleton method is at least free memory' do
81
+ expect(described_class.available).to be >= described_class.free
82
+ end
83
+ end
84
+
71
85
  context 'Sys::Memory.used' do
72
86
  example 'the used singleton method is defined' do
73
87
  expect(described_class).to respond_to(:used)
data/sys-memory.gemspec CHANGED
@@ -2,14 +2,14 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'sys-memory'
5
- spec.version = '0.2.1'
5
+ spec.version = '0.3.0'
6
6
  spec.author = 'Daniel J. Berger'
7
7
  spec.email = 'djberg96@gmail.com'
8
8
  spec.license = 'Apache-2.0'
9
9
  spec.homepage = 'https://github.com/djberg96/sys-memory'
10
10
  spec.summary = 'A Ruby interface for providing memory information'
11
11
  spec.test_file = 'spec/sys_memory_spec.rb'
12
- spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
12
+ spec.files = Dir['**/*'].reject{ |f| f.include?('git') || f.end_with?('.gem') }
13
13
  spec.cert_chain = ['certs/djberg96_pub.pem']
14
14
 
15
15
  spec.add_dependency('ffi', '~> 1.1')
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sys-memory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
metadata.gz.sig CHANGED
Binary file