Skip to content

Commit 09e5aa8

Browse files
committed
memory: substract zfs arc cache from used memory
1 parent 8659b3b commit 09e5aa8

4 files changed

Lines changed: 52 additions & 4 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ require (
5454
github.com/tklauser/numcpus v0.11.0 // indirect
5555
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
5656
github.com/yusufpapurcu/wmi v1.2.4 // indirect
57-
golang.org/x/exp v0.0.0-20260211191109-2735e65f0518 // indirect
57+
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect
5858
golang.org/x/sys v0.41.0 // indirect
5959
golang.org/x/text v0.34.0 // indirect
6060
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu
102102
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
103103
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
104104
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
105-
golang.org/x/exp v0.0.0-20260211191109-2735e65f0518 h1:2E1CW7v5QB+Wi3N+MXllOtVR6SFmI8iJM8EdzgxrgrU=
106-
golang.org/x/exp v0.0.0-20260211191109-2735e65f0518/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
105+
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o=
106+
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
107107
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
108108
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
109109
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=

gops/memory.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package gops
22

33
import (
4+
"bufio"
5+
"os"
6+
"strconv"
7+
"strings"
8+
49
"github.com/AvengeMedia/dgop/models"
510
)
611

@@ -16,10 +21,26 @@ func (self *GopsUtil) GetMemoryInfo() (*models.MemoryInfo, error) {
1621
cached := v.Cached / 1024
1722
sreclaimable := v.Sreclaimable / 1024
1823
shared := v.Shared / 1024
24+
available := v.Available / 1024
1925

2026
// gopsutil Cached includes SReclaimable, get raw value
2127
rawCached := cached - sreclaimable
2228

29+
// ZFS ARC is reclaimable cache not reflected in /proc/meminfo.
30+
// Read it from /proc/spl/kstat/zfs/arcstats (same approach as btop).
31+
arcSize, arcMin := readZfsArcStats()
32+
arcSizeKB := arcSize / 1024
33+
arcMinKB := arcMin / 1024
34+
35+
var freeableArc uint64
36+
switch {
37+
case arcSizeKB > arcMinKB:
38+
freeableArc = arcSizeKB - arcMinKB
39+
}
40+
41+
rawCached += arcSizeKB
42+
available += freeableArc
43+
2344
// Used = Total - Free - Cached - SReclaimable - Buffers + Shared
2445
usedDiff := free + rawCached + sreclaimable + buffers
2546
var used uint64
@@ -40,12 +61,38 @@ func (self *GopsUtil) GetMemoryInfo() (*models.MemoryInfo, error) {
4061
Used: used,
4162
UsedPercent: usedPercent,
4263
Free: free,
43-
Available: v.Available / 1024,
64+
Available: available,
4465
Buffers: buffers,
4566
Cached: rawCached,
4667
SReclaimable: sreclaimable,
4768
Shared: shared,
69+
ZfsArcSize: arcSizeKB,
4870
SwapTotal: v.SwapTotal / 1024,
4971
SwapFree: v.SwapFree / 1024,
5072
}, nil
5173
}
74+
75+
// readZfsArcStats reads ARC size and c_min from /proc/spl/kstat/zfs/arcstats.
76+
// Returns (0, 0) if ZFS is not present.
77+
func readZfsArcStats() (size uint64, cMin uint64) {
78+
f, err := os.Open("/proc/spl/kstat/zfs/arcstats")
79+
if err != nil {
80+
return 0, 0
81+
}
82+
defer f.Close()
83+
84+
scanner := bufio.NewScanner(f)
85+
for scanner.Scan() {
86+
fields := strings.Fields(scanner.Text())
87+
if len(fields) != 3 {
88+
continue
89+
}
90+
switch fields[0] {
91+
case "size":
92+
size, _ = strconv.ParseUint(fields[2], 10, 64)
93+
case "c_min":
94+
cMin, _ = strconv.ParseUint(fields[2], 10, 64)
95+
}
96+
}
97+
return size, cMin
98+
}

models/memory.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type MemoryInfo struct {
1010
Cached uint64 `json:"cached"`
1111
SReclaimable uint64 `json:"sreclaimable"`
1212
Shared uint64 `json:"shared"`
13+
ZfsArcSize uint64 `json:"zfsArcSize"`
1314
SwapTotal uint64 `json:"swaptotal"`
1415
SwapFree uint64 `json:"swapfree"`
1516
}

0 commit comments

Comments
 (0)