Make memory logging configurable 50/247350/13
authorYoungjae Cho <y0.cho@samsung.com>
Tue, 10 Nov 2020 05:09:13 +0000 (14:09 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Wed, 11 Nov 2020 08:40:17 +0000 (17:40 +0900)
Logging section in memory.conf file now configures the memory
logging. Now it is able to set the path and prefix of a logfile,
maximum number of logfiles, or even disable logging itself.

Change-Id: Id18da1b8df4ab4ba346080ad17f7c59da60acccb
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
src/common/memory-common.h
src/memory/lowmem-limit.c
src/memory/memory.conf
src/memory/vmpressure-lowmem-handler.c
tests/lowmem-limit-env.cpp
tests/lowmem-limit-env.hpp
tests/lowmem-limit-mock.cpp

index cd98ec1..3195cb0 100644 (file)
@@ -69,6 +69,12 @@ enum lowmem_control_type {
        LOWMEM_MANAGE_FOREGROUND,
 };
 
+enum mem_log {
+       MEMLOG_MEMPS,
+       MEMLOG_MEMPS_MEMLIMIT,
+       MEMLOG_MAX,
+};
+
 /* number of memory cgroups */
 #define MEMCG_DEFAULT_EVENT_LEVEL              "low"
 #define MEMCG_DEFAULT_USE_HIERARCHY            0
@@ -93,8 +99,8 @@ enum lowmem_control_type {
 #define MEMCG_SWAP_LIMIT_PATH  "memory.memsw.limit_in_bytes"
 #define MEMCG_SWAPPINESS_PATH     "memory.swappiness"
 
-#define MEMPS_LOG_PATH                 "/var/log"
-#define MEMPS_LOG_FILE                 MEMPS_LOG_PATH"/memps"
+#define DEFAULT_MEMLOG_PATH            "/var/log"
+#define DEFAULT_MEMLOG_NR_MAX  50
 
 struct memcg_info {
        /* name of memory cgroup */
@@ -155,6 +161,6 @@ int memcg_set_eventfd(const char *memcg, const char *event, char *value);
 /**
  * @desc execute /usr/bin/memps and make log file with pid and process name
  */
-void make_memps_log(char *file, pid_t pid, char *victim_name);
+void make_memps_log(enum mem_log path, pid_t pid, char *victim_name);
 
 #endif /*__MEMORY_COMMONL_H__*/
index 4599fcb..4f8459b 100644 (file)
@@ -53,7 +53,6 @@
 #include "safe-kill.h"
 
 #define MEM_CONF_FILE                   RD_CONFIG_FILE(memory)
-#define MEMLIMIT_LOG_FILE                      MEMPS_LOG_PATH"/memps_memlimit"
 #define MEMLIMIT_CONFIG_SECTION        "MemLimit"
 #define MEMLIMIT_CONFIG_TRIGGER        "MemLimitTrigger"
 #define MEMLIMIT_CONFIG_SERVICE        "MemLimitService"
@@ -184,7 +183,7 @@ static int make_memlimit_logs(void *data)
                exec_cmd(ARRAY_SIZE(argv), argv);
        }
 
-       make_memps_log(MEMLIMIT_LOG_FILE, mlog->pid, mlog->appname);
+       make_memps_log(MEMLOG_MEMPS_MEMLIMIT, mlog->pid, mlog->appname);
        return RESOURCED_ERROR_NONE;
 }
 
index cd65314..cc720df 100644 (file)
@@ -206,3 +206,14 @@ MemLimitTrigger=oom
 # How long does the resourced allow that each service applications use memory
 # But, it only allows to enable when the MemLimitTrigger option is oom or threshold.
 MemLimitService=128            # MB
+
+[Logging]
+Enable=1
+# memps logpath
+#              memps: OOM log
+#              memps_memlimit: lowmem limit log
+MaxNumLogfile=50       # default: 50
+LogPath=/var/log       # default: /var/log
+# logfile prefix
+PrefixMemps=memps
+PrefixMempsMemLimit=memps_memlimit
index 31fea00..c1b10a6 100644 (file)
@@ -82,6 +82,7 @@
 #define MEM_POPUP_STRING               "oom_popup"
 #define MEM_BG_RECLAIM_SECTION "BackgroundReclaim"
 #define MEM_BG_RECLAIM_STRING          "AfterScreenDim"
+#define MEM_LOGGING_SECTION            "Logging"
 
 #define BUF_MAX                                1024
 #define MAX_VICTIMS_BETWEEN_CHECK      3
@@ -90,8 +91,6 @@
 #define FOREGROUND_VICTIMS             1
 #define OOM_TIMER_INTERVAL             2
 #define OOM_KILLER_PRIORITY            -20
-#define MAX_MEMPS_LOGS                  50
-#define NUM_RM_LOGS                    5
 #define THRESHOLD_MARGIN               10 /* MB */
 
 #define MEM_SIZE_64                    64  /* MB */
@@ -222,6 +221,14 @@ struct lowmem_worker {
 
 static struct lowmem_worker lmw;
 
+static int memlog_enabled;
+static int memlog_nr_max = DEFAULT_MEMLOG_NR_MAX;
+/* remove logfiles to reduce to this threshold.
+ * it is about five-sixths of the memlog_nr_max. */
+static int memlog_remove_batch_thres = (DEFAULT_MEMLOG_NR_MAX * 5) / 6;
+static char *memlog_path = DEFAULT_MEMLOG_PATH;
+static char *memlog_prefix[MEMLOG_MAX];
+
 #define LOWMEM_WORKER_IS_ACTIVE(_lmw)  g_atomic_int_get(&(_lmw)->active)
 #define LOWMEM_WORKER_ACTIVATE(_lmw)   g_atomic_int_set(&(_lmw)->active, 1)
 #define LOWMEM_WORKER_DEACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 0)
@@ -462,7 +469,7 @@ static int timesort(const struct dirent **a, const struct dirent **b)
        return (time1 - time2);
 }
 
-int clear_logs(void *data)
+static int clear_logs(void *data)
 {
        struct dirent **namelist;
        int n, i, ret;
@@ -471,10 +478,11 @@ int clear_logs(void *data)
        char *dir = (char*)data;
        int len;
 
-       if (!dir) {
-               _E("Invalid parameter - dir is NULL");
-               return RESOURCED_ERROR_INVALID_PARAMETER;
-       }
+       if (!memlog_enabled)
+               return RESOURCED_ERROR_NONE;
+
+       if (!dir)
+               return RESOURCED_ERROR_NONE;
 
        len = strlen(dir);
        if (len <= 0 || len >= sizeof fpath - 1) {
@@ -483,8 +491,9 @@ int clear_logs(void *data)
        }
 
        n = scandir(dir, &namelist, memps_file_select, timesort);
+
        _D("num of log files %d", n);
-       if (n < MAX_MEMPS_LOGS) {
+       if (n <= memlog_nr_max) {
                while (n--)
                        free(namelist[n]);
                free(namelist);
@@ -498,7 +507,7 @@ int clear_logs(void *data)
 
        len = sizeof fpath - len - 1;
        for (i = 0; i < n; i++) {
-               if (i < NUM_RM_LOGS) {
+               if (i < n - memlog_remove_batch_thres) {
                        if (strlen(namelist[i]->d_name) > len - 1)
                                continue;
                        strncpy(fname, namelist[i]->d_name, len - 1);
@@ -515,16 +524,26 @@ int clear_logs(void *data)
        return RESOURCED_ERROR_NONE;
 }
 
-void make_memps_log(char *file, pid_t pid, char *victim_name)
+void make_memps_log(enum mem_log memlog, pid_t pid, char *victim_name)
 {
        time_t now;
        struct tm cur_tm;
        char new_log[BUF_MAX];
        static pid_t old_pid;
        int oom_score_adj = 0, ret;
+       char *prefix;
+
+       if (!memlog_enabled)
+               return;
+
+       if (memlog < MEMLOG_MEMPS || memlog >= MEMLOG_MAX)
+               return;
+
+       prefix = memlog_prefix[memlog];
 
        if (old_pid == pid)
                return;
+
        old_pid = pid;
 
        now = time(NULL);
@@ -535,7 +554,7 @@ void make_memps_log(char *file, pid_t pid, char *victim_name)
        }
 
        snprintf(new_log, sizeof(new_log),
-               "%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", file, victim_name,
+               "%s/%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", memlog_path, prefix, victim_name,
                pid, (1900 + cur_tm.tm_year), 1 + cur_tm.tm_mon,
                cur_tm.tm_mday, cur_tm.tm_hour, cur_tm.tm_min,
                cur_tm.tm_sec);
@@ -559,6 +578,9 @@ void make_memps_log(char *file, pid_t pid, char *victim_name)
                argv[2] = new_log;
                exec_cmd(ARRAY_SIZE(argv), argv);
        }
+
+       /* best effort to limit the number of logfiles up to memlog_nr_max */
+       clear_logs(memlog_path);
 }
 
 static int lowmem_kill_victim(const struct task_info *tsk,
@@ -587,7 +609,7 @@ static int lowmem_kill_victim(const struct task_info *tsk,
        }
 
        if (!memps_log)
-               make_memps_log(MEMPS_LOG_FILE, pid, appname);
+               make_memps_log(MEMLOG_MEMPS, pid, appname);
 
 
        pai = find_app_info(pid);
@@ -627,7 +649,7 @@ static int lowmem_kill_victim(const struct task_info *tsk,
                oom_popup = true;
        }
        if (memps_log)
-               make_memps_log(MEMPS_LOG_FILE, pid, appname);
+               make_memps_log(MEMLOG_MEMPS, pid, appname);
 
        return RESOURCED_ERROR_NONE;
 }
@@ -1076,8 +1098,8 @@ done:
        _E("Done: killed %d processes reclaimed: %u remaining: %u shortfall: %u status: %d\n",
                count, total_size, reclaim_size, shortfall, status);
        /* After we finish reclaiming it's worth to remove oldest memps logs */
-       if (count)
-               request_helper_worker(CLEAR_LOGS, MEMPS_LOG_PATH, clear_logs, NULL);
+       if (count && memlog_enabled)
+               request_helper_worker(CLEAR_LOGS, memlog_path, clear_logs, NULL);
        ctl->status = status;
 }
 
@@ -1508,6 +1530,30 @@ static int load_mem_config(struct parse_result *result, void *user_data)
        return RESOURCED_ERROR_NONE;
 }
 
+static int load_mem_logconfig(struct parse_result *result, void *user_data)
+{
+       if (!result)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (strncmp(result->section, MEM_LOGGING_SECTION, strlen(MEM_LOGGING_SECTION)+1))
+               return RESOURCED_ERROR_NONE;
+
+       if (!strncmp(result->name, "Enable", strlen("Enable")+1)) {
+               memlog_enabled = atoi(result->value);
+       } else if (!strncmp(result->name, "LogPath", strlen("LogPath")+1)) {
+               memlog_path = strdup(result->value);
+       } else if (!strncmp(result->name, "MaxNumLogfile", strlen("MaxNumLogfile")+1)) {
+               memlog_nr_max = atoi(result->value);
+               memlog_remove_batch_thres = (memlog_nr_max * 5) / 6;
+       } else if (!strncmp(result->name, "PrefixMemps", strlen("PrefixMemps")+1)) {
+               memlog_prefix[MEMLOG_MEMPS] = strdup(result->value);
+       } else if (!strncmp(result->name, "PrefixMempsMemLimit", strlen("PrefixMempsMemLimit")+1)) {
+               memlog_prefix[MEMLOG_MEMPS_MEMLIMIT] = strdup(result->value);
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
 static int set_memory_config(const char *section_name, const struct parse_result *result)
 {
        if (!result || !section_name)
@@ -2314,6 +2360,7 @@ static int lowmem_init(void)
        free_vip_app_list();
        config_parse(MEM_CONF_FILE, load_mem_config, NULL);
        config_parse(MEM_CONF_FILE, load_bg_reclaim_config, NULL);
+       config_parse(MEM_CONF_FILE, load_mem_logconfig, NULL);
 
        create_memcgs();
        write_memcg_params();
index 2c29d44..b246297 100644 (file)
@@ -277,10 +277,10 @@ int LowmemLimitEnv::exec_cmd(int argc, const char *argv[])
        return 0;
 }
 
-void LowmemLimitEnv::make_memps_log(char *file, pid_t pid, char *victim_name)
+void LowmemLimitEnv::make_memps_log(enum mem_log path, pid_t pid, char *victim_name)
 {
        // IGNORE THIS CALL
-       (void) file;
+       (void) path;
        (void) pid;
        (void) victim_name;
 }
index 7e91b5b..0816ec2 100644 (file)
@@ -28,6 +28,7 @@ extern "C" {
 #include "config-parser.h"
 #include "fd-handler.h"
 #include "proc-common.h"
+#include "memory-common.h"
 #include "resourced.h"
 #include "resourced-helper-worker.h"
 }
@@ -110,7 +111,7 @@ public:
        int add_fd_read_handler(int fd, fd_changed_cb callback,
                        void *data, release_cb free_func, fd_handler_h *handler);
 
-       void make_memps_log(char *file, pid_t pid, char *victim_name);
+       void make_memps_log(enum mem_log path, pid_t pid, char *victim_name);
 
        int cgroup_get_pids(const char *name, GArray **pids);
        int cgroup_write_node_uint32(const char *cgroup_name, const char *file_name, uint32_t value);
index 5765b9f..e03d1b0 100644 (file)
@@ -37,7 +37,7 @@ MOCK_LIMIT(int, proc_get_cmdline, (pid_t pid, char *cmdline, size_t maxcmdline),
 MOCK_LIMIT(proc_app_info *, find_app_info, (const pid_t pid), (pid))
 
 MOCK_LIMIT(int, exec_cmd, (int argc, const char *argv[]), (argc, argv))
-MOCK_LIMIT(void, make_memps_log, (char *file, pid_t pid, char *victim_name), (file, pid, victim_name))
+MOCK_LIMIT(void, make_memps_log, (enum mem_log path, pid_t pid, char *victim_name), (path, pid, victim_name))
 
 MOCK_LIMIT(int, cgroup_get_pids, (const char *name, GArray **pids), (name, pids))
 MOCK_LIMIT(int, cgroup_write_node_uint32,