#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 {
}
/**
- * @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)
{
}
/**
- * @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;
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;
}
/**
- * @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;
}
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;
}