Skip to content

Commit 8c169d7

Browse files
committed
(FACT-2805) Read available memory from MemAvailable
Available memory should use the new MemAvailable info in /proc/meminfo when available. When not, fall back to the formula used in facter 3 (MemFree + Cached + Buffers) For capacity, just use Total - Available
1 parent 0a2f78f commit 8c169d7

3 files changed

Lines changed: 119 additions & 31 deletions

File tree

lib/facter/resolvers/memory_resolver.rb

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,21 @@ def read_meminfo_file(fact_name)
2525

2626
def read_system(output)
2727
@fact_list[:total] = kilobytes_to_bytes(output.match(/MemTotal:\s+(\d+)\s/)[1])
28-
@fact_list[:memfree] = kilobytes_to_bytes(output.match(/MemFree:\s+(\d+)\s/)[1])
29-
@fact_list[:used_bytes] = compute_used(@fact_list[:total], reclaimable_memory(output))
28+
@fact_list[:memfree] = memfree(output)
29+
@fact_list[:used_bytes] = compute_used(@fact_list[:total], @fact_list[:memfree])
3030
@fact_list[:capacity] = compute_capacity(@fact_list[:used_bytes], @fact_list[:total])
3131
end
3232

33+
def memfree(output)
34+
available = output.match(/MemAvailable:\s+(\d+)\s/)
35+
return kilobytes_to_bytes(available[1]) if available
36+
37+
buffers = kilobytes_to_bytes(output.match(/Buffers:\s+(\d+)\s/)[1])
38+
cached = kilobytes_to_bytes(output.match(/Cached:\s+(\d+)\s/)[1])
39+
memfree = kilobytes_to_bytes(output.match(/MemFree:\s+(\d+)\s/)[1])
40+
memfree + buffers + cached
41+
end
42+
3343
def read_swap(output)
3444
total = output.match(/SwapTotal:\s+(\d+)\s/)[1]
3545
return if total.to_i.zero?
@@ -44,18 +54,6 @@ def kilobytes_to_bytes(quantity)
4454
quantity.to_i * 1024
4555
end
4656

47-
def reclaimable_memory(output)
48-
buffers = kilobytes_to_bytes(output.match(/Buffers:\s+(\d+)\s/)[1])
49-
cached = kilobytes_to_bytes(output.match(/Cached:\s+(\d+)\s/)[1])
50-
s_reclaimable = output.match(/SReclaimable:\s+(\d+)\s/)
51-
s_reclaimable = if s_reclaimable
52-
kilobytes_to_bytes(s_reclaimable[1])
53-
else
54-
0
55-
end
56-
@fact_list[:memfree] + buffers + cached + s_reclaimable
57-
end
58-
5957
def compute_capacity(used, total)
6058
format('%<computed_capacity>.2f', computed_capacity: (used / total.to_f * 100)) + '%'
6159
end

spec/facter/resolvers/memory_resolver_spec.rb

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@
1616

1717
context 'when there is swap memory' do
1818
let(:total) { 4_036_680 * 1024 }
19-
let(:free) { 3_547_792 * 1024 }
20-
let(:buffers) { 4_288 * 1024 }
21-
let(:cached) { 298_624 * 1024 }
22-
let(:s_reclaimable) { 29_072 * 1024 }
23-
let(:used) { total - free - buffers - cached - s_reclaimable }
19+
let(:available) { 3_659_324 * 1024 }
20+
let(:used) { total - available }
2421
let(:swap_total) { 2_097_148 * 1024 }
2522
let(:swap_free) { 2_097_148 * 1024 }
2623
let(:swap_used) { swap_total - swap_free }
@@ -31,7 +28,7 @@
3128
end
3229

3330
it 'returns memfree' do
34-
expect(resolver.resolve(:memfree)).to eq(free)
31+
expect(resolver.resolve(:memfree)).to eq(available)
3532
end
3633

3734
it 'returns swap total' do
@@ -65,19 +62,16 @@
6562

6663
context 'when there is not swap memory' do
6764
let(:total) { 4_134_510_592 }
68-
let(:free) { 3_465_723_904 }
69-
let(:buffers) { 2_088 * 1024 }
70-
let(:cached) { 445_204 * 1024 }
71-
let(:s_reclaimable) { 71_384 * 1024 }
72-
let(:used) { total - free - buffers - cached - s_reclaimable }
65+
let(:available) { 3_665_024 * 1024 }
66+
let(:used) { total - available }
7367
let(:fixture_name) { 'meminfo2' }
7468

7569
it 'returns total memory' do
7670
expect(resolver.resolve(:total)).to eq(total)
7771
end
7872

7973
it 'returns memfree' do
80-
expect(resolver.resolve(:memfree)).to eq(free)
74+
expect(resolver.resolve(:memfree)).to eq(available)
8175
end
8276

8377
it 'returns swap total as nil' do
@@ -109,22 +103,68 @@
109103

110104
context 'when on Rhel 5' do
111105
let(:total) { 4_036_680 * 1024 }
112-
let(:free) { 3_547_792 * 1024 }
106+
let(:available) { 3_659_324 * 1024 }
107+
let(:used) { total - available }
108+
let(:swap_total) { 2_097_148 * 1024 }
109+
let(:swap_free) { 2_097_148 * 1024 }
110+
let(:swap_used) { swap_total - swap_free }
111+
let(:fixture_name) { 'rhel5_memory' }
112+
113+
it 'returns total memory' do
114+
expect(resolver.resolve(:total)).to eq(total)
115+
end
116+
117+
it 'returns memfree' do
118+
expect(resolver.resolve(:memfree)).to eq(available)
119+
end
120+
121+
it 'returns swap total' do
122+
expect(resolver.resolve(:swap_total)).to eq(swap_total)
123+
end
124+
125+
it 'returns swap available' do
126+
expect(resolver.resolve(:swap_free)).to eq(swap_free)
127+
end
128+
129+
it 'returns swap capacity' do
130+
swap_capacity = format('%<swap_capacity>.2f', swap_capacity: (swap_used / swap_total.to_f * 100)) + '%'
131+
132+
expect(resolver.resolve(:swap_capacity)).to eq(swap_capacity)
133+
end
134+
135+
it 'returns swap usage' do
136+
expect(resolver.resolve(:swap_used_bytes)).to eq(swap_used)
137+
end
138+
139+
it 'returns system capacity' do
140+
system_capacity = format('%<capacity>.2f', capacity: (used / total.to_f * 100)) + '%'
141+
142+
expect(resolver.resolve(:capacity)).to eq(system_capacity)
143+
end
144+
145+
it 'returns system usage' do
146+
expect(resolver.resolve(:used_bytes)).to eq(used)
147+
end
148+
end
149+
150+
context 'when there is no available memory' do
151+
let(:total) { 4_036_680 * 1024 }
113152
let(:buffers) { 4_288 * 1024 }
114153
let(:cached) { 298_624 * 1024 }
115-
let(:s_reclaimable) { 0 }
116-
let(:used) { total - free - buffers - cached - s_reclaimable }
154+
let(:free) { 3_547_792 * 1024 }
155+
let(:available) { free + buffers + cached }
156+
let(:used) { total - available }
117157
let(:swap_total) { 2_097_148 * 1024 }
118158
let(:swap_free) { 2_097_148 * 1024 }
119159
let(:swap_used) { swap_total - swap_free }
120-
let(:fixture_name) { 'rhel5_memory' }
160+
let(:fixture_name) { 'meminfo_missing_available' }
121161

122162
it 'returns total memory' do
123163
expect(resolver.resolve(:total)).to eq(total)
124164
end
125165

126166
it 'returns memfree' do
127-
expect(resolver.resolve(:memfree)).to eq(free)
167+
expect(resolver.resolve(:memfree)).to eq(available)
128168
end
129169

130170
it 'returns swap total' do
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
MemTotal: 4036680 kB
2+
MemFree: 3547792 kB
3+
Buffers: 4288 kB
4+
Cached: 298624 kB
5+
SwapCached: 0 kB
6+
Active: 81968 kB
7+
Inactive: 255516 kB
8+
Active(anon): 35056 kB
9+
Inactive(anon): 264 kB
10+
Active(file): 46912 kB
11+
Inactive(file): 255252 kB
12+
Unevictable: 0 kB
13+
Mlocked: 0 kB
14+
SwapTotal: 2097148 kB
15+
SwapFree: 2097148 kB
16+
Dirty: 216 kB
17+
Writeback: 0 kB
18+
AnonPages: 34656 kB
19+
Mapped: 84464 kB
20+
Shmem: 680 kB
21+
KReclaimable: 29072 kB
22+
Slab: 80056 kB
23+
SReclaimable: 29072 kB
24+
SUnreclaim: 50984 kB
25+
KernelStack: 2688 kB
26+
PageTables: 1704 kB
27+
NFS_Unstable: 0 kB
28+
Bounce: 0 kB
29+
WritebackTmp: 0 kB
30+
CommitLimit: 4115488 kB
31+
Committed_AS: 274552 kB
32+
VmallocTotal: 34359738367 kB
33+
VmallocUsed: 0 kB
34+
VmallocChunk: 0 kB
35+
Percpu: 1728 kB
36+
HardwareCorrupted: 0 kB
37+
AnonHugePages: 0 kB
38+
ShmemHugePages: 0 kB
39+
ShmemPmdMapped: 0 kB
40+
CmaTotal: 0 kB
41+
CmaFree: 0 kB
42+
HugePages_Total: 0
43+
HugePages_Free: 0
44+
HugePages_Rsvd: 0
45+
HugePages_Surp: 0
46+
Hugepagesize: 2048 kB
47+
Hugetlb: 0 kB
48+
DirectMap4k: 100224 kB
49+
DirectMap2M: 4093952 kB
50+
DirectMap1G: 2097152 kB

0 commit comments

Comments
 (0)