Files
og/internal/hoststats/memory_darwin.go
T
2026-09-11 06:14:38 +02:00

67 lines
1.5 KiB
Go

//go:build darwin
package hoststats
import (
"bufio"
"context"
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
)
var pageSizeRE = regexp.MustCompile(`page size of ([0-9]+) bytes`)
func readMemory(ctx context.Context) (Memory, error) {
totalOut, err := exec.CommandContext(ctx, "/usr/sbin/sysctl", "-n", "hw.memsize").Output()
if err != nil {
return Memory{}, err
}
total, err := strconv.ParseInt(strings.TrimSpace(string(totalOut)), 10, 64)
if err != nil || total <= 0 {
return Memory{}, fmt.Errorf("invalid hw.memsize")
}
out, err := exec.CommandContext(ctx, "/usr/bin/vm_stat").Output()
if err != nil {
return Memory{}, err
}
pageSize := int64(4096)
var freePages int64
s := bufio.NewScanner(strings.NewReader(string(out)))
first := true
for s.Scan() {
line := s.Text()
if first {
first = false
if m := pageSizeRE.FindStringSubmatch(line); len(m) == 2 {
if v, e := strconv.ParseInt(m[1], 10, 64); e == nil {
pageSize = v
}
}
continue
}
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
name := strings.TrimSpace(parts[0])
v := strings.TrimSpace(strings.TrimSuffix(parts[1], "."))
n, _ := strconv.ParseInt(v, 10, 64)
switch name {
case "Pages free", "Pages inactive", "Pages speculative":
freePages += n
}
}
available := freePages * pageSize
used := total - available
if used < 0 {
used = 0
}
if used > total {
used = total
}
return Memory{TotalBytes: total, UsedBytes: used}, nil
}