Files
go2rtc/internal/api/system_darwin.go
T
Sergey Krashevich 0b80fa53cf feat(api): add system resource monitoring functionality
- implement getSystemInfo to gather CPU and memory usage
- add platform-specific implementations for memory and CPU usage
- enhance OpenAPI documentation to include system resource metrics
2026-02-13 14:49:20 +03:00

105 lines
2.1 KiB
Go

//go:build darwin
package api
import (
"os/exec"
"runtime"
"strconv"
"strings"
"syscall"
"unsafe"
)
func getMemoryInfo() (total, used uint64) {
total = sysctl64("hw.memsize")
if total == 0 {
return 0, 0
}
pageSize, err := syscall.SysctlUint32("hw.pagesize")
if err != nil {
return total, 0
}
freeCount, _ := syscall.SysctlUint32("vm.page_free_count")
purgeableCount, _ := syscall.SysctlUint32("vm.page_purgeable_count")
speculativeCount, _ := syscall.SysctlUint32("vm.page_speculative_count")
// inactive pages not available via sysctl, parse vm_stat
inactiveCount := vmStatPages("Pages inactive")
available := uint64(freeCount+purgeableCount+speculativeCount)*uint64(pageSize) +
inactiveCount*uint64(pageSize)
if available > total {
return total, 0
}
return total, total - available
}
// vmStatPages parses vm_stat output for a specific counter
func vmStatPages(key string) uint64 {
out, err := exec.Command("vm_stat").Output()
if err != nil {
return 0
}
for _, line := range strings.Split(string(out), "\n") {
if strings.HasPrefix(line, key) {
// format: "Pages inactive: 479321."
parts := strings.Split(line, ":")
if len(parts) < 2 {
continue
}
s := strings.TrimSpace(parts[1])
s = strings.TrimSuffix(s, ".")
val, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return 0
}
return val
}
}
return 0
}
func sysctl64(name string) uint64 {
s, err := syscall.Sysctl(name)
if err != nil {
return 0
}
b := []byte(s)
for len(b) < 8 {
b = append(b, 0)
}
return *(*uint64)(unsafe.Pointer(&b[0]))
}
func getCPUUsage() float64 {
s, err := syscall.Sysctl("vm.loadavg")
if err != nil {
return 0
}
raw := []byte(s)
for len(raw) < 24 {
raw = append(raw, 0)
}
// struct loadavg { fixpt_t ldavg[3]; long fscale; }
ldavg0 := *(*uint32)(unsafe.Pointer(&raw[0]))
fscale := *(*int64)(unsafe.Pointer(&raw[16]))
if fscale == 0 {
return 0
}
load1 := float64(ldavg0) / float64(fscale)
numCPU := float64(runtime.NumCPU())
usage := load1 / numCPU * 100
if usage > 100 {
usage = 100
}
return usage
}