From 6c598e8341c202a61dc24678f4450fd5af961b4e Mon Sep 17 00:00:00 2001 From: Ryan King Date: Fri, 11 Apr 2025 13:28:22 -0400 Subject: [PATCH] std: add os.linux.sysinfo(), use it for process.totalSystemMemory() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alex Rønne Petersen --- lib/std/os/linux.zig | 65 +++++++++++++++++++++++++++++++++++++++ lib/std/os/linux/test.zig | 9 ++++++ lib/std/process.zig | 23 ++++---------- 3 files changed, 80 insertions(+), 17 deletions(-) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 9d85bf9000..00390c0800 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -2610,6 +2610,71 @@ pub fn map_shadow_stack(addr: u64, size: u64, flags: u32) usize { return syscall3(.map_shadow_stack, addr, size, flags); } +pub const Sysinfo = switch (native_abi) { + .gnux32, .muslx32 => extern struct { + /// Seconds since boot + uptime: i64, + /// 1, 5, and 15 minute load averages + loads: [3]u64, + /// Total usable main memory size + totalram: u64, + /// Available memory size + freeram: u64, + /// Amount of shared memory + sharedram: u64, + /// Memory used by buffers + bufferram: u64, + /// Total swap space size + totalswap: u64, + /// swap space still available + freeswap: u64, + /// Number of current processes + procs: u16, + /// Explicit padding for m68k + pad: u16, + /// Total high memory size + totalhigh: u64, + /// Available high memory size + freehigh: u64, + /// Memory unit size in bytes + mem_unit: u32, + }, + else => extern struct { + /// Seconds since boot + uptime: isize, + /// 1, 5, and 15 minute load averages + loads: [3]usize, + /// Total usable main memory size + totalram: usize, + /// Available memory size + freeram: usize, + /// Amount of shared memory + sharedram: usize, + /// Memory used by buffers + bufferram: usize, + /// Total swap space size + totalswap: usize, + /// swap space still available + freeswap: usize, + /// Number of current processes + procs: u16, + /// Explicit padding for m68k + pad: u16, + /// Total high memory size + totalhigh: usize, + /// Available high memory size + freehigh: usize, + /// Memory unit size in bytes + mem_unit: u32, + /// Pad + _f: [20 - 2 * @sizeOf(usize) - @sizeOf(u32)]u8, + }, +}; + +pub fn sysinfo(info: *Sysinfo) usize { + return syscall1(.sysinfo, @intFromPtr(info)); +} + pub const E = switch (native_arch) { .mips, .mipsel, .mips64, .mips64el => enum(u16) { /// No error occurred. diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index 27d156e9cc..fa6f822329 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -165,6 +165,15 @@ test "sigset_t" { try expectEqual(sigset[2], 0); } +test "sysinfo" { + var info: linux.Sysinfo = undefined; + const result: usize = linux.sysinfo(&info); + try expect(std.os.linux.E.init(result) == .SUCCESS); + + try expect(info.mem_unit > 0); + try expect(info.mem_unit <= std.heap.page_size_max); +} + test { _ = linux.IoUring; } diff --git a/lib/std/process.zig b/lib/std/process.zig index 7751b88b14..072cbeefdb 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1748,7 +1748,12 @@ pub const TotalSystemMemoryError = error{ pub fn totalSystemMemory() TotalSystemMemoryError!u64 { switch (native_os) { .linux => { - return totalSystemMemoryLinux() catch return error.UnknownTotalSystemMemory; + var info: std.os.linux.Sysinfo = undefined; + const result: usize = std.os.linux.sysinfo(&info); + if (std.os.linux.E.init(result) != .SUCCESS) { + return error.UnknownTotalSystemMemory; + } + return info.totalram * info.mem_unit; }, .freebsd => { var physmem: c_ulong = undefined; @@ -1793,22 +1798,6 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 { } } -fn totalSystemMemoryLinux() !u64 { - var file = try std.fs.openFileAbsoluteZ("/proc/meminfo", .{}); - defer file.close(); - var buf: [50]u8 = undefined; - const amt = try file.read(&buf); - if (amt != 50) return error.Unexpected; - var it = std.mem.tokenizeAny(u8, buf[0..amt], " \n"); - const label = it.next().?; - if (!std.mem.eql(u8, label, "MemTotal:")) return error.Unexpected; - const int_text = it.next() orelse return error.Unexpected; - const units = it.next() orelse return error.Unexpected; - if (!std.mem.eql(u8, units, "kB")) return error.Unexpected; - const kilobytes = try std.fmt.parseInt(u64, int_text, 10); - return kilobytes * 1024; -} - /// Indicate that we are now terminating with a successful exit code. /// In debug builds, this is a no-op, so that the calling code's /// cleanup mechanisms are tested and so that external tools that