memory : make a config file to configure memory-killer module 63/179663/14
authorKichan Kwon <k_c.kwon@samsung.com>
Mon, 21 May 2018 04:48:41 +0000 (13:48 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Thu, 2 Aug 2018 04:54:27 +0000 (13:54 +0900)
- The maximum number of victims
- Threshold : medium and leave
- Whitelist : exclude from being victim

Change-Id: Iafa92a31fd0fe43b269fd66ea383d01417c8ac26
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
CMakeLists.txt
cfg/memory.conf [new file with mode: 0644]
packaging/resourced-headless.spec
src/common/macro.h
src/memory/memory-common.h
src/memory/memory-killer.c
src/memory/memory-killer.h
src/memory/memory.c

index ad9916ca28802c2b7e5c366a2a6f7fd8fb100a06..b76ed34f57bc03efebce5c8ce4d3059030e90c98 100644 (file)
@@ -73,6 +73,7 @@ ENDIF()
 
 IF("${MEMORY_MODULE}" STREQUAL "ON")
        BUILD_MODULE("${PKGNAME}-memory" "memory" "library")
+       ADD_CONFIG("memory")
 ENDIF()
 
 IF("${TEST_MODULE}" STREQUAL "ON")
diff --git a/cfg/memory.conf b/cfg/memory.conf
new file mode 100644 (file)
index 0000000..f430b9c
--- /dev/null
@@ -0,0 +1,17 @@
+[memory-killer]
+# The maximum number of victims
+# If insufficient memory is retained after kill N apps, memory-killer will kill N more processes
+# MEMORY_SIZE  :  ~256MB  ~512MB  ~768MB  ~1024MB  ~2048MB     UPPER
+NumMaxVictims=         2;      5;      5;       5;      10;  # MEMORY_SIZE(MB) / 200
+
+[memory-killer.threshold]
+# Medium : Threshold to start low memory killer
+# Leave : Threshold to stop low memory killer
+# MEMORY_SIZE  :  ~256MB  ~512MB  ~768MB  ~1024MB  ~2048MB        UPPER
+Medium=               10;     60;     80;     100;     160  # MB  MEMORY_SIZE * 10%
+Leave=                20;     80;    100;     150;     300  # MB  MEMORY_SIZE * 15%
+
+[memory-killer.whitelist]
+# Exclude BASENAME from being victim
+# BASENAME=exclude_victim
+crash-worker=exclude_victim
index 91cf9ff41c4a4eefa86590280ae481e2c0ab71e5..97c1e112e24fd3d7a13d77cbe67e4eb737c72aeb 100644 (file)
@@ -115,6 +115,7 @@ install -m 0644 %{SOURCE102} %{buildroot}%{_sysconfdir}/dbus-1/system.d/resource
 %license LICENSE
 %manifest %{name}-memory.manifest
 %{_libdir}/libresourced-headless-memory.so*
+%config %{config_install_dir}/memory.conf
 %endif
 
 %if %{proc_usage_module} == ON
index 9dc7e53c8cf5b53d8b0a0fee324d58b0c72748a8..337fce959b7d890189adb0f4cf3f5c7d6a179c7c 100644 (file)
 
 #define BYTE_TO_KBYTE(b) ((b) >> 10)
 
+#define KBYTE_TO_MBYTE(k) ((k) >> 10)
+
+#define MBYTE_TO_KBYTE(m) ((m) << 10)
+
 #define PAGE_TO_KBYTE(p) ((p) << 2)
 
 #endif /* __RESOURCED_HEADLESS_MACRO_H__ */
index 055173e0a48e9dca2c153928444e2ae621be7359..d0baefbec7027361bfe9046b6aeb8761786bd3d2 100644 (file)
 #ifndef __RESOURCED_HEADLESS_MEMORY_COMMON_H__
 #define __RESOURCED_HEADLESS_MEMORY_COMMON_H__
 
+#include <macro.h>
+
+#define MEMORY_CONFIG_FILE_NAME  "memory"
+
 /**
  * @brief  Local event for memory module
  */
index d68bbb8954f270e2b566298c0c50dc22f373fe57..c47000d68433dab27e066f3b750c57632094058c 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 
 #include <cgroup.h>
+#include <config-parser.h>
 #include <event.h>
 #include <log.h>
 #include <macro.h>
 #include "memory-common.h"
 #include "memory-killer.h"
 
-static int memory_killer_max_victim = 1;
+/**
+ * @brief  Config file related macro
+ */
+#define MEMORY_KILLER_GROUP           "memory-killer"
+#define MEMORY_KILLER_MAX_VICTIM_KEY  "NumMaxVictims"
+
+#define MEMORY_KILLER_THRESHOLD_GROUP  MEMORY_KILLER_GROUP".threshold"
+
+#define MEMORY_KILLER_WHITELIST_GROUP  MEMORY_KILLER_GROUP".whitelist"
+
+/**
+ * @details  Default max_victim = MEMORY_SIZE(MB) / DEFAULT_DENOMINATOR
+ */
+#define MKMV_DEFAULT_DENOMINATOR 200
+
+static unsigned int memory_killer_max_victim = 1;
 
+/**
+ * @details  Key(basename), Value(NULL)
+ */
 static GHashTable *memory_killer_whitelist;
 
+static unsigned int mem_total; /* kB */
+static enum memory_killer_config_unit memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_UPPER;
+
 static unsigned int mem_available;     /* kB */
 
 struct memory_killer_threshold {
+       const char *name;
+       const int default_ratio;        /* % */
        unsigned int threshold; /* kB */
-       const double default_ratio;     /* % */
 };
 
 static struct memory_killer_threshold mkts[MEMORY_LEVEL_MAX] = {
-       { 0, 1.0 },
-       { 0, 0.1 }
+       { "Normal", 100, 0 },
+       { "Medium", 10, 0 }
 };
 
 static struct memory_killer_threshold mkt_leave = {
-       0, 0.15
+       "Leave", 15, 0
 };
 
 struct memory_killer_candidate {
@@ -167,7 +190,7 @@ static int memory_killer_get_candidates(enum memory_killer_range range, GSList *
 }
 
 /**
- * @retval  0 on success, otherwise a negative error value
+ * @return  0 on success, otherwise a negative error value
  */
 static int memory_killer_work_normal(void)
 {
@@ -175,13 +198,13 @@ static int memory_killer_work_normal(void)
 }
 
 /**
- * @retval  0 on success, otherwise a negative error value
+ * @return  0 on success, otherwise a negative error value
  */
 static int memory_killer_work_medium(void)
 {
        enum memory_killer_range range = MEMORY_KILLER_RANGE_ONLY_APP;
        int ret;
-       int num_killed;
+       unsigned int num_killed;
        int wait_count;
        long long need_to_retain;
        GSList *candidates = NULL;
@@ -253,6 +276,9 @@ retain_memory:
        return 0;
 }
 
+/**
+ * @return  current memory pressure level on success, otherwise MEMORY_LEVEL_INVALID
+ */
 static enum memory_level memory_killer_get_memory_level(void)
 {
        int ret;
@@ -311,40 +337,168 @@ static gboolean memory_killer_notify(gpointer user_data)
 }
 
 /**
- * @brief  Add a whitelist which isn't be victim by memory-killer
+ * @brief  Set config unit according to memory size
+ */
+static void memory_killer_set_config_unit(void)
+{
+       unsigned int mem_total_mb = KBYTE_TO_MBYTE(mem_total);
+
+       if (mem_total_mb < 256)
+               memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_256MB;
+       else if (mem_total_mb < 512)
+               memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_512MB;
+       else if (mem_total_mb < 768)
+               memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_768MB;
+       else if (mem_total_mb < 1024)
+               memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_1024MB;
+       else if (mem_total_mb < 2048)
+               memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_2048MB;
+       else
+               memory_killer_config_unit = MEMORY_KILLER_CONFIG_UNIT_UPPER;
+}
+
+static void memory_killer_set_max_victim(void)
+{
+       int ret;
+       int mv;
+       size_t mv_list_len;
+       int *mv_list = NULL;
+
+       memory_killer_max_victim = KBYTE_TO_MBYTE(mem_total) / MKMV_DEFAULT_DENOMINATOR;
+
+       /* CONFIG_UNIT_UPPER is impervious to config file */
+       if (memory_killer_config_unit == MEMORY_KILLER_CONFIG_UNIT_UPPER)
+               return;
+
+       ret = config_parser_get_int_list(MEMORY_CONFIG_FILE_NAME, MEMORY_KILLER_GROUP,
+                       MEMORY_KILLER_MAX_VICTIM_KEY, &mv_list, &mv_list_len);
+       if (ret < 0) {
+               _D("Failed to read the maximum number of victims (%d). Set to default value", ret);
+               return;
+       }
+
+       if (mv_list_len <= memory_killer_config_unit) {
+               _D("There is no configuration for config unit %u. Set to default value",
+                               memory_killer_config_unit);
+               goto clean;
+       }
+
+       mv = mv_list[memory_killer_config_unit];
+
+       if (mv < 0) {
+               _D("Invalid maximum victims (%d). Set to default value", mv);
+               goto clean;
+       }
+
+       memory_killer_max_victim = mv;
+       _D("Set the maximum number of victims with %u", memory_killer_max_victim);
+
+clean:
+       if (mv_list)
+               free(mv_list);
+}
+
+/**
+ * @brief  Set threshold with config file's or default value
  */
-static void memory_killer_add_whitelist(char *name)
+static void memory_killer_set_threshold(struct memory_killer_threshold *mkt)
 {
-       char *key;
+       int ret;
+       int threshold;
+       size_t threshold_list_len;
+       int *threshold_list = NULL;
+
+       if (!mkt || !mkt->name) {
+               _E("Invalid argument");
+               return;
+       }
 
-       if (!memory_killer_whitelist) {
-               memory_killer_whitelist = g_hash_table_new_full(g_str_hash, g_str_equal,
-                               g_free, NULL);
-               g_assert(memory_killer_whitelist);
+       /* Normal threshold is fixed with memory size */
+       if (!strncmp(mkt->name, "Normal", 7)) {
+               mkt->threshold = mem_total;
+               return;
        }
 
-       key = strndup(name, strlen(name));
-       g_hash_table_add(memory_killer_whitelist, key);
+       mkt->threshold = mem_total / 100 * mkt->default_ratio;
+
+       /* CONFIG_UNIT_UPPER is impervious to config file */
+       if (memory_killer_config_unit == MEMORY_KILLER_CONFIG_UNIT_UPPER)
+               return;
+
+       ret = config_parser_get_int_list(MEMORY_CONFIG_FILE_NAME, MEMORY_KILLER_THRESHOLD_GROUP,
+                       mkt->name, &threshold_list, &threshold_list_len);
+       if (ret < 0) {
+               _D("Failed to read %s threshold (%d). Set to default value", mkt->name, ret);
+               return;
+       }
+
+       if (threshold_list_len <= memory_killer_config_unit) {
+               _D("There is no configuration for config unit %u. Set to default value",
+                               memory_killer_config_unit);
+               goto clean;
+       }
+
+       threshold = MBYTE_TO_KBYTE(threshold_list[memory_killer_config_unit]);
+
+       if (threshold <= 0 || threshold >= mem_total) {
+               _D("Invalid %s threshold (%d kB). Set to default value", mkt->name, threshold);
+               goto clean;
+       }
+
+       mkt->threshold = threshold;
+       _D("Set %s threshold to %u kB", mkt->name, mkt->threshold);
+
+clean:
+       if (threshold_list)
+               free(threshold_list);
 }
 
-static int memory_killer_set_threshold(void)
+/**
+ * @brief  Add a whitelist which isn't be victim by memory-killer
+ */
+static void memory_killer_add_whitelist(const char *key, const void *not_used)
+{
+       gchar *basename;
+
+       basename = g_strndup(key, strlen(key));
+       g_assert(basename);
+       g_hash_table_add(memory_killer_whitelist, basename);
+       _D("%s : whitelist", basename);
+}
+
+/**
+ * @brief  Read memory config file and configure this module
+ * @return  0 on success, otherwise a negative error value
+ */
+static int memory_killer_read_config(void)
 {
        int ret;
        int memory_level;
-       unsigned int mem_total;
        struct procfs_meminfo pm;
 
+       /* Get memory size */
        ret = procfs_get_meminfo(PROCFS_MEMINFO_MASK_MEM_TOTAL, &pm);
        if (ret < 0) {
                _E("Failed to get system memory information (%d)", ret);
                return ret;
        }
        mem_total = pm.value[PROCFS_MEMINFO_ID_MEM_TOTAL];
+       memory_killer_set_config_unit();
 
+       /* Set the maximum number of victims */
+       memory_killer_set_max_victim();
+
+       /* Set threshold */
        for (memory_level = 0; memory_level < MEMORY_LEVEL_MAX; memory_level++)
-               mkts[memory_level].threshold = mem_total * mkts[memory_level].default_ratio;
+               memory_killer_set_threshold(&mkts[memory_level]);
+       memory_killer_set_threshold(&mkt_leave);
 
-       mkt_leave.threshold = mem_total * mkt_leave.default_ratio;
+       /* Add whitelist */
+       memory_killer_whitelist = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+       _D("========== Memory-killer whitelist ==========");
+       config_parser_foreach(MEMORY_CONFIG_FILE_NAME, MEMORY_KILLER_WHITELIST_GROUP,
+                       memory_killer_add_whitelist);
+       _D("==========   Total %d process(es)   ==========", g_hash_table_size(memory_killer_whitelist));
 
        return 0;
 }
@@ -356,12 +510,9 @@ API int memory_killer_init(void)
        GIOChannel *channel;
        GSource *source;
 
-       memory_killer_add_whitelist("crash-worker");
-
-       ret = memory_killer_set_threshold();
+       ret = memory_killer_read_config();
        if (ret < 0) {
-               _E("Failed to set threshold (%d)", ret);
-               g_hash_table_destroy(memory_killer_whitelist);
+               _E("Failed to read config file (%d)", ret);
                return ret;
        }
 
index 00893fa424eac27a652cab1a0dc7ae393c81ace2..c186f76a970b9fc6af4180a7332977815d3389bc 100644 (file)
@@ -36,6 +36,22 @@ enum memory_killer_range {
        MEMORY_KILLER_RANGE_MAX
 };
 
+/**
+ * @brief  Configuration unit
+ * @detail  Some configurations (like threshold) are set
+ *          according to target's memory size.
+ *          CONFIG_UNIT_X is chosen if target has X-1 ~ X RAM
+ *          e.g) CONFIG_UNIT_1024MB : 768MB < MEMORY_SIZE <= 1024MB
+ */
+enum memory_killer_config_unit {
+       MEMORY_KILLER_CONFIG_UNIT_256MB = 0,
+       MEMORY_KILLER_CONFIG_UNIT_512MB,
+       MEMORY_KILLER_CONFIG_UNIT_768MB,
+       MEMORY_KILLER_CONFIG_UNIT_1024MB,
+       MEMORY_KILLER_CONFIG_UNIT_2048MB,
+       MEMORY_KILLER_CONFIG_UNIT_UPPER
+};
+
 /**
  * @brief  Check current memory level and do appropriate processing
  * @return  0 on success, otherwise a negative return value
index de21f14e58ebd835e5ffe72312ea187ebdabd05b..ce69a59c3fc7937460947078a3a2885f770eb822 100644 (file)
@@ -19,6 +19,7 @@
 #include <glib.h>
 #include <stdio.h>
 
+#include <config-parser.h>
 #include <event.h>
 #include <log.h>
 #include <macro.h>
@@ -48,6 +49,12 @@ static int __INIT__ memory_init(void)
 {
        int ret;
 
+       ret = config_parser_open(MEMORY_CONFIG_FILE_NAME);
+       if (ret < 0) {
+               _E("Failed to open memory config file (%d)", ret);
+               return ret;
+       }
+
        ret = memory_killer_init();
        if (ret < 0) {
                _E("Failed to initialize memory killer (%d)", ret);
@@ -67,6 +74,8 @@ static int __EXIT__ memory_exit(void)
                return ret;
        }
 
+       config_parser_close(MEMORY_CONFIG_FILE_NAME);
+
        return 0;
 }