mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-13 13:53:43 +00:00
Merge pull request #6765 from MightyChubz/fix/linux-inaccurate-meminfo
fix: Get meminfo from `/proc/meminfo` over `sysinfo()`
This commit is contained in:
@@ -2,6 +2,7 @@ package sysinfo
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:sys/linux"
|
||||
|
||||
@@ -80,16 +81,98 @@ _os_version :: proc (allocator: runtime.Allocator, loc := #caller_location) -> (
|
||||
|
||||
@(private)
|
||||
_ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) {
|
||||
// Retrieve RAM info using `sysinfo`
|
||||
sys_info: linux.Sys_Info
|
||||
errno := linux.sysinfo(&sys_info)
|
||||
assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
|
||||
// This is here for some of the strings procedures
|
||||
context = runtime.default_context()
|
||||
|
||||
total_ram = i64(sys_info.totalram) * i64(sys_info.mem_unit)
|
||||
free_ram = i64(sys_info.freeram) * i64(sys_info.mem_unit)
|
||||
total_swap = i64(sys_info.totalswap) * i64(sys_info.mem_unit)
|
||||
free_swap = i64(sys_info.freeswap) * i64(sys_info.mem_unit)
|
||||
ok = true
|
||||
// The approach is to read /proc/meminfo for the memory information. We do this over
|
||||
// reading sysinfo() since sysinfo() only returns MemFree, which is based on the amount
|
||||
// of free pages. The value we actually want is MemAvailable inside meminfo since it is
|
||||
// estimated around being about to evict things out of the page cache.
|
||||
fd, errno := linux.open("/proc/meminfo", {})
|
||||
if errno != .NONE {
|
||||
// This should never happen since something would be wrong with the system
|
||||
// if /proc/meminfo wasn't able to be opened for any reason. But, in the
|
||||
// event that this _does_ happen, let's just try to recover through the
|
||||
// syscall
|
||||
sys_info: linux.Sys_Info
|
||||
sysinfo_errno := linux.sysinfo(&sys_info)
|
||||
assert_contextless(sysinfo_errno == .NONE, "If this has failed, there is no recovery from this")
|
||||
|
||||
total_ram = i64(sys_info.totalram) * i64(sys_info.mem_unit)
|
||||
free_ram = i64(sys_info.freeram) * i64(sys_info.mem_unit)
|
||||
total_swap = i64(sys_info.totalswap) * i64(sys_info.mem_unit)
|
||||
free_swap = i64(sys_info.freeswap) * i64(sys_info.mem_unit)
|
||||
|
||||
ok = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
defer linux.close(fd)
|
||||
|
||||
// We need a relatively large size to store all the info
|
||||
meminfo_buf: [4096]u8
|
||||
n, read_errno := linux.read(fd, meminfo_buf[:])
|
||||
if read_errno != .NONE {
|
||||
sys_info: linux.Sys_Info
|
||||
sysinfo_errno := linux.sysinfo(&sys_info)
|
||||
assert_contextless(sysinfo_errno == .NONE, "If this has failed, there is no recovery from this")
|
||||
|
||||
total_ram = i64(sys_info.totalram) * i64(sys_info.mem_unit)
|
||||
free_ram = i64(sys_info.freeram) * i64(sys_info.mem_unit)
|
||||
total_swap = i64(sys_info.totalswap) * i64(sys_info.mem_unit)
|
||||
free_swap = i64(sys_info.freeswap) * i64(sys_info.mem_unit)
|
||||
|
||||
ok = true
|
||||
|
||||
return
|
||||
}
|
||||
meminfo := string(meminfo_buf[:n])
|
||||
|
||||
// Fallback in the event MemAvailable is not found or is invalid in its value
|
||||
mem_free: i64
|
||||
|
||||
mem_unit :: 1024
|
||||
for line in strings.split_lines_iterator(&meminfo) {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
colon_idx := strings.index(line, ":")
|
||||
if colon_idx < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
key := strings.trim_space(line[:colon_idx])
|
||||
value_str := strings.trim_space(strings.trim_suffix(line[colon_idx + 1:], "kB"))
|
||||
|
||||
value, conv_ok := strconv.parse_i64(value_str, 10)
|
||||
if !conv_ok {
|
||||
continue
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "MemTotal":
|
||||
total_ram = value * mem_unit
|
||||
case "MemFree":
|
||||
mem_free = value * mem_unit
|
||||
case "MemAvailable":
|
||||
free_ram = value * mem_unit
|
||||
case "SwapTotal":
|
||||
total_swap = value * mem_unit
|
||||
case "SwapFree":
|
||||
free_swap = value * mem_unit
|
||||
}
|
||||
}
|
||||
|
||||
if free_ram == 0 || free_ram > total_ram {
|
||||
// We opt to return MemFree here if MemAvailable is not found or is broken to some degree.
|
||||
// This will act as a predictable fallback, but shouldn't ever really occur unless the user
|
||||
// is on Linux < 3.14
|
||||
free_ram = mem_free
|
||||
}
|
||||
|
||||
ok = true
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user