]> Skullheadx's Git Forge - slstatus.git/commitdiff
more concise memory calculation on Linux
authordrkhsh <me@drkhsh.at>
Thu, 24 Jul 2025 20:41:25 +0000 (22:41 +0200)
committerdrkhsh <me@drkhsh.at>
Thu, 24 Jul 2025 20:41:25 +0000 (22:41 +0200)
more flexible parsing for /proc/meminfo to take shared and reclaimable
memory into account. this matches the output with free(1).

additionally this could fix some corner cases, as the order of fields in
/proc/meminfo is not strictly defined.

slstatus:
percent 81% free 2.5 Gi total 23.4 Gi used 19.0 Gi

free(1):
               total        used        free      shared  buff/cache   available
Mem:            23Gi        19Gi       2.5Gi       1.3Gi       3.2Gi       3.6Gi

components/ram.c
util.c
util.h

index 15c4b74f16c1711779b3dd6244c6e79892a49219..bf71dcfcc3fb0bf2033992eda27a99781c366c8a 100644 (file)
        ram_free(const char *unused)
        {
                uintmax_t free;
+               FILE *fp;
 
-               if (pscanf("/proc/meminfo",
-                          "MemTotal: %ju kB\n"
-                          "MemFree: %ju kB\n"
-                          "MemAvailable: %ju kB\n",
-                          &free, &free, &free) != 3)
+               if (!(fp = fopen("/proc/meminfo", "r")))
                        return NULL;
 
+               if (lscanf(fp, "MemFree:", "%ju kB", &free) != 1) {
+                       fclose(fp);
+                       return NULL;
+               }
+
+               fclose(fp);
                return fmt_human(free * 1024, 1024);
        }
 
        const char *
        ram_perc(const char *unused)
        {
-               uintmax_t total, free, buffers, cached;
+               uintmax_t total, free, buffers, cached, shmem, sreclaimable;
                int percent;
+               FILE *fp;
+
+               if (!(fp = fopen("/proc/meminfo", "r")))
+                       return NULL;
 
-               if (pscanf("/proc/meminfo",
-                          "MemTotal: %ju kB\n"
-                          "MemFree: %ju kB\n"
-                          "MemAvailable: %ju kB\n"
-                          "Buffers: %ju kB\n"
-                          "Cached: %ju kB\n",
-                          &total, &free, &buffers, &buffers, &cached) != 5)
+               if (lscanf(fp, "MemTotal:", "%ju kB", &total)  != 1 ||
+                   lscanf(fp, "MemFree:", "%ju kB", &free)    != 1 ||
+                   lscanf(fp, "Buffers:", "%ju kB", &buffers) != 1 ||
+                   lscanf(fp, "Cached:", "%ju kB", &cached)   != 1 ||
+                   lscanf(fp, "Shmem:", "%ju kB", &shmem)     != 1 ||
+                   lscanf(fp, "SReclaimable:", "%ju kB", &sreclaimable) != 1) {
+                       fclose(fp);
                        return NULL;
+               }
+               fclose(fp);
 
                if (total == 0)
                        return NULL;
 
-               percent = 100 * ((total - free) - (buffers + cached)) / total;
+               percent = 100 * (total - free - buffers - cached - sreclaimable + shmem) / total;
                return bprintf("%d", percent);
        }
 
        const char *
        ram_used(const char *unused)
        {
-               uintmax_t total, free, buffers, cached, used;
+               uintmax_t total, free, buffers, cached, used, shmem, sreclaimable;
+               FILE *fp;
+
+               if (!(fp = fopen("/proc/meminfo", "r")))
+                       return NULL;
 
-               if (pscanf("/proc/meminfo",
-                          "MemTotal: %ju kB\n"
-                          "MemFree: %ju kB\n"
-                          "MemAvailable: %ju kB\n"
-                          "Buffers: %ju kB\n"
-                          "Cached: %ju kB\n",
-                          &total, &free, &buffers, &buffers, &cached) != 5)
+               if (lscanf(fp, "MemTotal:", "%ju kB", &total)  != 1 ||
+                   lscanf(fp, "MemFree:", "%ju kB", &free)    != 1 ||
+                   lscanf(fp, "Buffers:", "%ju kB", &buffers) != 1 ||
+                   lscanf(fp, "Cached:", "%ju kB", &cached)   != 1 ||
+                   lscanf(fp, "Shmem:", "%ju kB", &shmem)     != 1 ||
+                   lscanf(fp, "SReclaimable:", "%ju kB", &sreclaimable) != 1) {
+                       fclose(fp);
                        return NULL;
+               }
+               fclose(fp);
 
-               used = (total - free - buffers - cached);
+               used = total - free - buffers - cached - sreclaimable + shmem;
                return fmt_human(used * 1024, 1024);
        }
 #elif defined(__OpenBSD__)
diff --git a/util.c b/util.c
index bca9b2eabff3d89d838c4b47c6a5870755ef330e..d33cf9d9469f5dd663b297049e7d7b89486b77a5 100644 (file)
--- a/util.c
+++ b/util.c
@@ -139,3 +139,20 @@ pscanf(const char *path, const char *fmt, ...)
 
        return (n == EOF) ? -1 : n;
 }
+
+int
+lscanf(FILE *fp, const char *key, const char *fmt, void *res)
+{
+               int n;
+               char line[256];
+
+               n = -1;
+               while (fgets(line, sizeof(line), fp))
+                       if (strncmp(line, key, strlen(key)) == 0) {
+                               n = sscanf(line + strlen(key), fmt, res);
+                               break;
+                       }
+
+               rewind(fp);
+               return (n == 1) ? 1 : -1;
+}
diff --git a/util.h b/util.h
index cf4b0273185f8d8f39ffc86a310ad36d5c89af1c..7a960aadc1b12a3d449d398ae6895f00c3da14e0 100644 (file)
--- a/util.h
+++ b/util.h
@@ -1,5 +1,6 @@
 /* See LICENSE file for copyright and license details. */
 #include <stdint.h>
+#include <stdio.h>
 
 extern char buf[1024];
 
@@ -14,3 +15,4 @@ int esnprintf(char *str, size_t size, const char *fmt, ...);
 const char *bprintf(const char *fmt, ...);
 const char *fmt_human(uintmax_t num, int base);
 int pscanf(const char *path, const char *fmt, ...);
+int lscanf(FILE *fp, const char *key, const char *fmt, void *res);