Commit 6c598e8341

Ryan King <root@ryank.ing>
2025-04-11 19:28:22
std: add os.linux.sysinfo(), use it for process.totalSystemMemory()
Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
1 parent 933beb4
Changed files (3)
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;
 }
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.
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