ohmu
·
2026-10-15
1#include "memory.h"
2#include "common/debug.h"
3#include "common/io.h"
4
5const char* ffDetectMemory(FFMemoryResult* ram) {
6 char buf[PROC_FILE_BUFFSIZ];
7 ssize_t nRead = ffReadFileData("/proc/meminfo", ARRAY_SIZE(buf) - 1, buf);
8 if (nRead < 0) {
9 FF_DEBUG("ffReadFileData(\"/proc/meminfo\", ARRAY_SIZE(buf)-1, buf) failed: %s", strerror(errno));
10 return "ffReadFileData(\"/proc/meminfo\", ARRAY_SIZE(buf)-1, buf)";
11 }
12 buf[nRead] = '\0';
13
14 uint64_t memTotal = 0,
15 memAvailable = 0,
16 shmem = 0,
17 memFree = 0,
18 buffers = 0,
19 cached = 0,
20 sReclaimable = 0;
21
22 char* token = nullptr;
23 if ((token = memmem(buf, (size_t) nRead, "MemTotal:", strlen("MemTotal:"))) != nullptr) {
24 memTotal = (uint64_t) strtoull(token + strlen("MemTotal:"), nullptr, 10);
25 } else {
26 FF_DEBUG("MemTotal not found in /proc/meminfo");
27 return "MemTotal not found in /proc/meminfo";
28 }
29
30 if ((token = memmem(buf, (size_t) nRead, "MemAvailable:", strlen("MemAvailable:"))) != nullptr) {
31 memAvailable = (uint64_t) strtoull(token + strlen("MemAvailable:"), nullptr, 10);
32 }
33
34 if (memAvailable == 0 || memAvailable >= memTotal) { // MemAvailable can be unreasonable. #1988
35 if ((token = memmem(buf, (size_t) nRead, "MemFree:", strlen("MemFree:"))) != nullptr) {
36 memFree = (uint64_t) strtoull(token + strlen("MemFree:"), nullptr, 10);
37 }
38
39 if ((token = memmem(buf, (size_t) nRead, "Buffers:", strlen("Buffers:"))) != nullptr) {
40 buffers = (uint64_t) strtoull(token + strlen("Buffers:"), nullptr, 10);
41 }
42
43 if ((token = memmem(buf, (size_t) nRead, "Cached:", strlen("Cached:"))) != nullptr) {
44 cached = (uint64_t) strtoull(token + strlen("Cached:"), nullptr, 10);
45 }
46
47 if ((token = memmem(buf, (size_t) nRead, "Shmem:", strlen("Shmem:"))) != nullptr) {
48 shmem = (uint64_t) strtoull(token + strlen("Shmem:"), nullptr, 10);
49 }
50
51 if ((token = memmem(buf, (size_t) nRead, "SReclaimable:", strlen("SReclaimable:"))) != nullptr) {
52 sReclaimable = (uint64_t) strtoull(token + strlen("SReclaimable:"), nullptr, 10);
53 }
54
55 memAvailable = memFree + buffers + cached + sReclaimable - shmem;
56 }
57
58 ram->bytesTotal = memTotal * 1024lu;
59 ram->bytesUsed = (memTotal - memAvailable) * 1024lu;
60
61 uint64_t arcSize = 0;
62 nRead = ffReadFileData("/proc/spl/kstat/zfs/arcstats", ARRAY_SIZE(buf) - 1, buf);
63 if (nRead > 0) {
64 buf[nRead] = '\0';
65 // 24 1 0x01 148 40256 2053603602 851614020716
66 // name type data
67 // hits 4 752
68
69 // Skip first line
70 const char* p = memchr(buf, '\n', (size_t) nRead);
71 if (__builtin_expect(p != nullptr, true)) {
72 ++p;
73 nRead -= (p - buf);
74 assert(nRead > 0);
75
76 // Find line offset of data
77 const char* pData = memmem(p, (size_t) nRead, "data\n", strlen("data\n"));
78 if (__builtin_expect(pData != nullptr, true)) {
79 uint32_t dataOffset = (uint32_t) (pData - p);
80 p += dataOffset + strlen("data\n");
81 nRead -= (ssize_t) (dataOffset + strlen("data\n"));
82 assert(nRead > 0);
83
84 if ((token = memmem(p, (size_t) nRead, "\nsize ", strlen("\nsize "))) != nullptr) {
85 arcSize = (uint64_t) strtoull(token + 1 + dataOffset, nullptr, 10);
86 if (arcSize > 0) {
87 uint64_t arcMin = 0;
88 if ((token = memmem(p, (size_t) nRead, "\nc_min ", strlen("\nc_min "))) != nullptr) {
89 arcMin = (uint64_t) strtoull(token + 1 + dataOffset, nullptr, 10);
90 if (arcSize > arcMin) {
91 arcSize -= arcMin;
92 if (ram->bytesUsed > arcSize) {
93 ram->bytesUsed -= arcSize;
94 }
95 }
96 }
97 }
98 }
99 }
100 }
101 }
102
103 return nullptr;
104}