From a15a9cc1239be10c443a08c68950f15bb54929a1 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 14 Jul 2025 16:24:07 +0300 Subject: [PATCH] runtime: reduce allocations done in runtime.used_memory/0 on linux (#24901) --- vlib/runtime/used_memory_linux.c.v | 49 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/vlib/runtime/used_memory_linux.c.v b/vlib/runtime/used_memory_linux.c.v index 19b5a5d92f..f20403ee4a 100644 --- a/vlib/runtime/used_memory_linux.c.v +++ b/vlib/runtime/used_memory_linux.c.v @@ -3,17 +3,44 @@ module runtime import os // used_memory retrieves the current physical memory usage of the process. +@[manualfree] pub fn used_memory() !u64 { - file := '/proc/self/status' - content := os.read_file(file) or { return 0 } - for line in content.split_into_lines() { - if line.starts_with('VmRSS:') { - parts := line.split(':') - if parts.len > 1 { - value := parts[1].trim_space().replace('kB', '').trim_space() - return value.u64() * 1024 // Convert to bytes - } - } + buffer := [1024]u8{} + pc := unsafe { &buffer[0] } + // see https://man7.org/linux/man-pages/man5/proc_pid_stat.5.html for a detailed description of the format. + // Here is an example: + // 699989 (test_program) R 178038 699989 178038 34816 699989 0 102 0 0 0 0 0 0 0 20 0 1 0 84188763 5726208 129 18446744073709551615 93824992239616 93824992257073 140737488345056 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 93824992275088 93824992276672 93824992280576 140737488346201 140737488346221 140737488346221 140737488351211 0 + // => read the file in the fixed buffer, search to after the `)` to skip the variable name part, then scan till the `129` RSS value, and then convert it from pages to bytes. + mut f := os.open_file('/proc/self/stat', 'r')! + defer { f.close() } + read := f.read_into_ptr(pc, buffer.len)! + if read <= 0 { + return error('could not read from /proc/self/stat') + } + mut c := 0 + unsafe { + // scan to after the process name (`comm`) field: + for c < buffer.len && *pc != `)` { + pc++ + c++ + } + mut spaces := 0 + // the following fields, are space separated numbers, skip past them to the `rss` field: + for c < buffer.len && spaces < 22 { + if *pc == ` ` { + spaces++ + } + pc++ + c++ + } + mut ndigits := 0 + // scan till the end of the `rss` field: + for c < buffer.len && *(pc + ndigits) != ` ` { + ndigits++ + c++ + } + rss_pages := pc.vstring_with_len(ndigits).u64() + page_size := C.sysconf(C._SC_PAGESIZE) + return u64(rss_pages * page_size) } - return 0 }