libsystem: proc: add /proc/meminfo parse api
authorWaLyong Cho <walyong.cho@samsung.com>
Thu, 10 Nov 2016 10:36:04 +0000 (19:36 +0900)
committerWaLyong Cho <walyong.cho@samsung.com>
Thu, 10 Nov 2016 11:13:21 +0000 (20:13 +0900)
Change-Id: I74b0f5992d49428b13213aef6fcb8c200c0605d3
Signed-off-by: WaLyong Cho <walyong.cho@samsung.com>
src/Makefile.am
src/libsystem/.gitignore
src/libsystem/proc-meminfo-lookup.gperf [new file with mode: 0644]
src/libsystem/proc.c
src/libsystem/proc.h

index f1ca4cf..9378c18 100644 (file)
@@ -66,13 +66,16 @@ libsystem_la_SOURCES = \
        libsystem/libsystem.c \
        libsystem/libsystem.h \
        libsystem/proc.c \
+       libsystem/proc-meminfo-lookup.c \
        libsystem/proc-smaps-lookup.c \
        libsystem/time-util.c
 
 EXTRA_DIST += \
+       libsystem/proc-meminfo-lookup.gperf \
        libsystem/proc-smaps-lookup.gperf
 
 CLEANFILES += \
+       libsystem/proc-meminfo-lookup.c \
        libsystem/proc-smaps-lookup.c
 
 libsystem_la_CFLAGS = \
index fe4ac25..154d18c 100644 (file)
@@ -1,2 +1,3 @@
 /libsystem.pc
+/proc-meminfo-lookup.c
 /proc-smaps-lookup.c
\ No newline at end of file
diff --git a/src/libsystem/proc-meminfo-lookup.gperf b/src/libsystem/proc-meminfo-lookup.gperf
new file mode 100644 (file)
index 0000000..1ca9fbe
--- /dev/null
@@ -0,0 +1,67 @@
+%{
+#include <assert.h>
+#include "proc.h"
+
+struct meminfo_mapping {
+        const char *name;
+        enum meminfo_id id;
+};
+typedef struct meminfo_mapping meminfo_mapping;
+%}
+meminfo_mapping;
+%language=ANSI-C
+%define slot-name name
+%define hash-function-name meminfo_mapping_hash
+%define lookup-function-name meminfo_mapping_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+MemTotal,       MEMINFO_ID_MEM_TOTAL
+MemFree,        MEMINFO_ID_MEM_FREE
+MemAvailable,   MEMINFO_ID_MEM_AVAILABLE
+Buffers,        MEMINFO_ID_BUFFERS
+Cached,         MEMINFO_ID_CACHED
+SwapCached,     MEMINFO_ID_SWAP_CACHED
+Active,         MEMINFO_ID_ACTIVE
+Inactive,       MEMINFO_ID_INACTIVE
+Active(anon),   MEMINFO_ID_ACTIVE_ANON
+Inactive(anon), MEMINFO_ID_INACTIVE_ANON
+Active(file),   MEMINFO_ID_ACTIVE_FILE
+Inactive(file), MEMINFO_ID_INACTIVE_FILE
+Unevictable,    MEMINFO_ID_UNEVICTABLE
+Mlocked,        MEMINFO_ID_MLOCKED
+HighTotal,      MEMINFO_ID_HIGH_TOTAL
+HighFree,       MEMINFO_ID_HIGH_FREE
+LowTotal,       MEMINFO_ID_LOW_TOTAL
+LowFree,        MEMINFO_ID_LOW_FREE
+SwapTotal,      MEMINFO_ID_SWAP_TOTAL
+SwapFree,       MEMINFO_ID_SWAP_FREE
+Dirty,          MEMINFO_ID_DIRTY
+Writeback,      MEMINFO_ID_WRITEBACK
+AnonPages,      MEMINFO_ID_ANON_PAGES
+Mapped,         MEMINFO_ID_MAPPED
+Shmem,          MEMINFO_ID_SHMEM
+Slab,           MEMINFO_ID_SLAB
+SReclaimable,   MEMINFO_ID_SRECLAIMABLE
+SUnreclaim,     MEMINFO_ID_SUNRECLAIM
+KernelStack,    MEMINFO_ID_KERNEL_STACK
+PageTables,     MEMINFO_ID_PAGE_TABLES
+NFS_Unstable,   MEMINFO_ID_NFS_UNSTABLE
+Bounce,         MEMINFO_ID_BOUNCE
+WritebackTmp,   MEMINFO_ID_WRITEBACK_TMP
+CommitLimit,    MEMINFO_ID_COMMIT_LIMIT
+Committed_AS,   MEMINFO_ID_COMMITTED_AS
+VmallocTotal,   MEMINFO_ID_VMALLOC_TOTAL
+VmallocUsed,    MEMINFO_ID_VMALLOC_USED
+VmallocChunk,   MEMINFO_ID_VMALLOC_CHUNK
+%%
+enum meminfo_id meminfo_string_to_id(const char *str)
+{
+        const struct meminfo_mapping *i;
+
+        assert(str);
+        i = meminfo_mapping_lookup(str, strlen(str));
+        return i ? i->id : MEMINFO_ID_INVALID;
+}
index 38d5b93..d429cf3 100644 (file)
@@ -252,3 +252,108 @@ on_error:
         smaps_free(m);
         return r;
 }
+
+static const char* const meminfo_string_lookup[MEMINFO_ID_MAX] = {
+        [MEMINFO_ID_MEM_TOTAL]     = "MemTotal",
+        [MEMINFO_ID_MEM_FREE]      = "MemFree",
+        [MEMINFO_ID_MEM_AVAILABLE] = "MemAvailable",
+        [MEMINFO_ID_BUFFERS]       = "Buffers",
+        [MEMINFO_ID_CACHED]        = "Cached",
+        [MEMINFO_ID_SWAP_CACHED]   = "SwapCached",
+        [MEMINFO_ID_ACTIVE]        = "Active",
+        [MEMINFO_ID_INACTIVE]      = "Inactive",
+        [MEMINFO_ID_ACTIVE_ANON]   = "Active(anon)",
+        [MEMINFO_ID_INACTIVE_ANON] = "Inactive(anon)",
+        [MEMINFO_ID_ACTIVE_FILE]   = "Active(file)",
+        [MEMINFO_ID_INACTIVE_FILE] = "Inactive(file)",
+        [MEMINFO_ID_UNEVICTABLE]   = "Unevictable",
+        [MEMINFO_ID_MLOCKED]       = "Mlocked",
+        [MEMINFO_ID_HIGH_TOTAL]    = "HighTotal",
+        [MEMINFO_ID_HIGH_FREE]     = "HighFree",
+        [MEMINFO_ID_LOW_TOTAL]     = "LowTotal",
+        [MEMINFO_ID_LOW_FREE]      = "LowFree",
+        [MEMINFO_ID_SWAP_TOTAL]    = "SwapTotal",
+        [MEMINFO_ID_SWAP_FREE]     = "SwapFree",
+        [MEMINFO_ID_DIRTY]         = "Dirty",
+        [MEMINFO_ID_WRITEBACK]     = "Writeback",
+        [MEMINFO_ID_ANON_PAGES]    = "AnonPages",
+        [MEMINFO_ID_MAPPED]        = "Mapped",
+        [MEMINFO_ID_SHMEM]         = "Shmem",
+        [MEMINFO_ID_SLAB]          = "Slab",
+        [MEMINFO_ID_SRECLAIMABLE]  = "SReclaimable",
+        [MEMINFO_ID_SUNRECLAIM]    = "SUnreclaim",
+        [MEMINFO_ID_KERNEL_STACK]  = "KernelStack",
+        [MEMINFO_ID_PAGE_TABLES]   = "PageTables",
+        [MEMINFO_ID_NFS_UNSTABLE]  = "NFS_Unstable",
+        [MEMINFO_ID_BOUNCE]        = "Bounce",
+        [MEMINFO_ID_WRITEBACK_TMP] = "WritebackTmp",
+        [MEMINFO_ID_COMMIT_LIMIT]  = "CommitLimit",
+        [MEMINFO_ID_COMMITTED_AS]  = "Committed_AS",
+        [MEMINFO_ID_VMALLOC_TOTAL] = "VmallocTotal",
+        [MEMINFO_ID_VMALLOC_USED]  = "VmallocUsed",
+        [MEMINFO_ID_VMALLOC_CHUNK] = "VmallocChunk",
+};
+
+const char *meminfo_id_to_string(enum meminfo_id id) {
+        assert(id >= 0 && id < MEMINFO_ID_MAX);
+
+        return meminfo_string_lookup[id];
+}
+
+int proc_get_meminfo(struct meminfo *mi, enum meminfo_mask mask) {
+        _cleanup_fclose_ FILE *f = NULL;
+        enum meminfo_mask remain_mask = mask;
+        char buf[LINE_MAX];
+
+        assert(mi);
+
+        memset(mi, 0x0, sizeof(struct meminfo));
+
+        f = fopen("/proc/meminfo", "r");
+        if (!f)
+                return -errno;
+
+        if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE)
+                remain_mask |= (MEMINFO_MASK_MEM_FREE |
+                                MEMINFO_MASK_CACHED);
+
+        while (remain_mask) {
+                unsigned int v = 0;
+                enum meminfo_id id;
+                size_t l;
+
+                if (!fgets(buf, sizeof(buf), f)) {
+                        if (ferror(f))
+                                return -errno;
+                        break;
+                }
+
+                l = strcspn(buf, ":");
+                if (!l)
+                        break;
+
+                buf[l] = 0;
+
+                id = meminfo_string_to_id(buf);
+                if (id < 0 || id >= MEMINFO_ID_MAX)
+                        continue;
+
+                if (!(remain_mask & (1ULL << id)))
+                        continue;
+
+                remain_mask &= ~((1ULL << id));
+
+                if (sscanf(buf + l + 1, "%d", &v) != 1)
+                        break;
+
+                mi->value[id] = v;
+        }
+
+        if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE) {
+                mi->value[MEMINFO_ID_MEM_AVAILABLE] =
+                        mi->value[MEMINFO_ID_MEM_FREE]
+                        + mi->value[MEMINFO_ID_CACHED];
+        }
+
+        return 0;
+}
index 132da3c..935db2d 100644 (file)
@@ -228,6 +228,140 @@ enum smap_id smap_string_to_id(const char *str);
 int proc_pid_get_smaps(pid_t pid, struct smaps **maps, enum smap_mask mask);
 
 /**
+ * meminfo id
+ */
+enum meminfo_id {
+        MEMINFO_ID_INVALID = -1,
+        MEMINFO_ID_MEM_TOTAL = 0,
+        MEMINFO_ID_MEM_FREE,
+        MEMINFO_ID_MEM_AVAILABLE,
+        MEMINFO_ID_BUFFERS,
+        MEMINFO_ID_CACHED,
+        MEMINFO_ID_SWAP_CACHED,
+        MEMINFO_ID_ACTIVE,
+        MEMINFO_ID_INACTIVE,
+        MEMINFO_ID_ACTIVE_ANON,
+        MEMINFO_ID_INACTIVE_ANON,
+        MEMINFO_ID_ACTIVE_FILE,
+        MEMINFO_ID_INACTIVE_FILE,
+        MEMINFO_ID_UNEVICTABLE,
+        MEMINFO_ID_MLOCKED,
+        MEMINFO_ID_HIGH_TOTAL,
+        MEMINFO_ID_HIGH_FREE,
+        MEMINFO_ID_LOW_TOTAL,
+        MEMINFO_ID_LOW_FREE,
+        MEMINFO_ID_SWAP_TOTAL,
+        MEMINFO_ID_SWAP_FREE,
+        MEMINFO_ID_DIRTY,
+        MEMINFO_ID_WRITEBACK,
+        MEMINFO_ID_ANON_PAGES,
+        MEMINFO_ID_MAPPED,
+        MEMINFO_ID_SHMEM,
+        MEMINFO_ID_SLAB,
+        MEMINFO_ID_SRECLAIMABLE,
+        MEMINFO_ID_SUNRECLAIM,
+        MEMINFO_ID_KERNEL_STACK,
+        MEMINFO_ID_PAGE_TABLES,
+        MEMINFO_ID_NFS_UNSTABLE,
+        MEMINFO_ID_BOUNCE,
+        MEMINFO_ID_WRITEBACK_TMP,
+        MEMINFO_ID_COMMIT_LIMIT,
+        MEMINFO_ID_COMMITTED_AS,
+        MEMINFO_ID_VMALLOC_TOTAL,
+        MEMINFO_ID_VMALLOC_USED,
+        MEMINFO_ID_VMALLOC_CHUNK,
+        MEMINFO_ID_MAX,
+};
+
+/**
+ * meminfo mask
+ */
+enum meminfo_mask {
+        MEMINFO_MASK_MEM_TOTAL          = 1ULL << MEMINFO_ID_MEM_TOTAL,
+        MEMINFO_MASK_MEM_FREE           = 1ULL << MEMINFO_ID_MEM_FREE,
+        MEMINFO_MASK_MEM_AVAILABLE      = 1ULL << MEMINFO_ID_MEM_AVAILABLE,
+        MEMINFO_MASK_BUFFERS            = 1ULL << MEMINFO_ID_BUFFERS,
+        MEMINFO_MASK_CACHED             = 1ULL << MEMINFO_ID_CACHED,
+        MEMINFO_MASK_SWAP_CACHED        = 1ULL << MEMINFO_ID_SWAP_CACHED,
+        MEMINFO_MASK_ACTIVE             = 1ULL << MEMINFO_ID_ACTIVE,
+        MEMINFO_MASK_INACTIVE           = 1ULL << MEMINFO_ID_INACTIVE,
+        MEMINFO_MASK_ACTIVE_ANON        = 1ULL << MEMINFO_ID_ACTIVE_ANON,
+        MEMINFO_MASK_INACTIVE_ANON      = 1ULL << MEMINFO_ID_INACTIVE_ANON,
+        MEMINFO_MASK_ACTIVE_FILE        = 1ULL << MEMINFO_ID_ACTIVE_FILE,
+        MEMINFO_MASK_INACTIVE_FILE      = 1ULL << MEMINFO_ID_INACTIVE_FILE,
+        MEMINFO_MASK_UNEVICTABLE        = 1ULL << MEMINFO_ID_UNEVICTABLE,
+        MEMINFO_MASK_MLOCKED            = 1ULL << MEMINFO_ID_MLOCKED,
+        MEMINFO_MASK_HIGH_TOTAL         = 1ULL << MEMINFO_ID_HIGH_TOTAL,
+        MEMINFO_MASK_HIGH_FREE          = 1ULL << MEMINFO_ID_HIGH_FREE,
+        MEMINFO_MASK_LOW_TOTAL          = 1ULL << MEMINFO_ID_LOW_TOTAL,
+        MEMINFO_MASK_LOW_FREE           = 1ULL << MEMINFO_ID_LOW_FREE,
+        MEMINFO_MASK_SWAP_TOTAL         = 1ULL << MEMINFO_ID_SWAP_TOTAL,
+        MEMINFO_MASK_SWAP_FREE          = 1ULL << MEMINFO_ID_SWAP_FREE,
+        MEMINFO_MASK_DIRTY              = 1ULL << MEMINFO_ID_DIRTY,
+        MEMINFO_MASK_WRITEBACK          = 1ULL << MEMINFO_ID_WRITEBACK,
+        MEMINFO_MASK_ANON_PAGES         = 1ULL << MEMINFO_ID_ANON_PAGES,
+        MEMINFO_MASK_MAPPED             = 1ULL << MEMINFO_ID_MAPPED,
+        MEMINFO_MASK_SHMEM              = 1ULL << MEMINFO_ID_SHMEM,
+        MEMINFO_MASK_SLAB               = 1ULL << MEMINFO_ID_SLAB,
+        MEMINFO_MASK_SRECLAIMABLE       = 1ULL << MEMINFO_ID_SRECLAIMABLE,
+        MEMINFO_MASK_SUNRECLAIM         = 1ULL << MEMINFO_ID_SUNRECLAIM,
+        MEMINFO_MASK_KERNEL_STACK       = 1ULL << MEMINFO_ID_KERNEL_STACK,
+        MEMINFO_MASK_PAGE_TABLES        = 1ULL << MEMINFO_ID_PAGE_TABLES,
+        MEMINFO_MASK_NFS_UNSTABLE       = 1ULL << MEMINFO_ID_NFS_UNSTABLE,
+        MEMINFO_MASK_BOUNCE             = 1ULL << MEMINFO_ID_BOUNCE,
+        MEMINFO_MASK_WRITEBACK_TMP      = 1ULL << MEMINFO_ID_WRITEBACK_TMP,
+        MEMINFO_MASK_COMMIT_LIMIT       = 1ULL << MEMINFO_ID_COMMIT_LIMIT,
+        MEMINFO_MASK_COMMITTED_AS       = 1ULL << MEMINFO_ID_COMMITTED_AS,
+        MEMINFO_MASK_VMALLOC_TOTAL      = 1ULL << MEMINFO_ID_VMALLOC_TOTAL,
+        MEMINFO_MASK_VMALLOC_USED       = 1ULL << MEMINFO_ID_VMALLOC_USED,
+        MEMINFO_MASK_VMALLOC_CHUNK      = 1ULL << MEMINFO_ID_VMALLOC_CHUNK,
+        MEMINFO_MASK_ALL                = (1ULL << MEMINFO_ID_MAX) - 1,
+};
+
+/**
+ * meminfo
+ */
+struct meminfo {
+        unsigned int value[MEMINFO_ID_MAX];
+};
+
+/**
+ * @brief Convert meminfo id to string
+ *
+ * @param id meminfo id
+ *
+ * @return converted string
+ */
+const char *meminfo_id_to_string(enum meminfo_id id);
+
+/**
+ * @brief Convert meminfo string to id
+ *
+ * @param str meminfo string
+ *
+ * @return converted id
+ */
+enum meminfo_id meminfo_string_to_id(const char *str);
+
+/**
+ * @brief Get system memory info(/proc/meminfo)
+ * @code{.c}
+ unsigned int get_mem_available(void)
+ {
+        struct meminfo mi;
+
+        proc_get_meminfo(&mi, MEMINFO_MASK_MEM_AVAILABLE);
+ }
+ * @endcode
+ *
+ * @param mi parsed meminfo struct.
+ * @param mask mask to get meminfo.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int proc_get_meminfo(struct meminfo *mi, enum meminfo_mask mask);
+
+/**
  * @}
  */