11package gops
22
33import (
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+ }
0 commit comments