Skip to content

Commit a15a9cc

Browse files
authored
runtime: reduce allocations done in runtime.used_memory/0 on linux (#24901)
1 parent 1ea8574 commit a15a9cc

1 file changed

Lines changed: 36 additions & 9 deletions

File tree

‎vlib/runtime/used_memory_linux.c.v‎

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,44 @@ module runtime
33
import os
44

55
// used_memory retrieves the current physical memory usage of the process.
6+
@[manualfree]
67
pub fn used_memory() !u64 {
7-
file := '/proc/self/status'
8-
content := os.read_file(file) or { return 0 }
9-
for line in content.split_into_lines() {
10-
if line.starts_with('VmRSS:') {
11-
parts := line.split(':')
12-
if parts.len > 1 {
13-
value := parts[1].trim_space().replace('kB', '').trim_space()
14-
return value.u64() * 1024 // Convert to bytes
8+
buffer := [1024]u8{}
9+
pc := unsafe { &buffer[0] }
10+
// see https://man7.org/linux/man-pages/man5/proc_pid_stat.5.html for a detailed description of the format.
11+
// Here is an example:
12+
// 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
13+
// => 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.
14+
mut f := os.open_file('/proc/self/stat', 'r')!
15+
defer { f.close() }
16+
read := f.read_into_ptr(pc, buffer.len)!
17+
if read <= 0 {
18+
return error('could not read from /proc/self/stat')
19+
}
20+
mut c := 0
21+
unsafe {
22+
// scan to after the process name (`comm`) field:
23+
for c < buffer.len && *pc != `)` {
24+
pc++
25+
c++
26+
}
27+
mut spaces := 0
28+
// the following fields, are space separated numbers, skip past them to the `rss` field:
29+
for c < buffer.len && spaces < 22 {
30+
if *pc == ` ` {
31+
spaces++
1532
}
33+
pc++
34+
c++
35+
}
36+
mut ndigits := 0
37+
// scan till the end of the `rss` field:
38+
for c < buffer.len && *(pc + ndigits) != ` ` {
39+
ndigits++
40+
c++
1641
}
42+
rss_pages := pc.vstring_with_len(ndigits).u64()
43+
page_size := C.sysconf(C._SC_PAGESIZE)
44+
return u64(rss_pages * page_size)
1745
}
18-
return 0
1946
}

0 commit comments

Comments
 (0)