etmem/0067-etmem-add-swapcache-reclaim-to-etmem.patch
liubo fe6d2a0135 etmem: sync source repo submission
Sync the features and bug fixed in the etmem
source repository.

Signed-off-by: liubo <liubo254@huawei.com>
(cherry picked from commit 07dd6a411bce9ed3d9f617a6f01ae076e24a3adf)
2022-10-12 10:10:23 +08:00

553 lines
18 KiB
Diff

From 8a7c297694bfad83bdc826aea3c0fea84098a4fb Mon Sep 17 00:00:00 2001
From: liubo <liubo254@huawei.com>
Date: Tue, 18 Jan 2022 15:21:13 +0800
Subject: [PATCH 17/33] etmem: add swapcache reclaim to etmem
When etmem performs the memory swap operation, it will
occupy part of the swapcache memory. To further save
memory, the swapcache memory recovery function is
added, which depends on etmem_swap.ko
Add swapcache_high_wmark and swapcache_low_wmark field
to set the available watermark of swapcache memory.
When the swapcache memory usage is higher than high_wmark,
the swapcache memory recovery is triggered until it is less
than low wmark.
Signed-off-by: liubo <liubo254@huawei.com>
---
etmem/conf/slide_conf.yaml | 2 +
etmem/inc/etmemd_inc/etmemd_common.h | 50 ++++++++-----
etmem/inc/etmemd_inc/etmemd_migrate.h | 1 +
etmem/inc/etmemd_inc/etmemd_project_exp.h | 3 +
etmem/src/etmemd_src/etmemd_common.c | 48 +++++++------
etmem/src/etmemd_src/etmemd_cslide.c | 12 +++-
etmem/src/etmemd_src/etmemd_migrate.c | 113 +++++++++++++++++++++++++++++-
etmem/src/etmemd_src/etmemd_project.c | 56 ++++++++++++++-
etmem/src/etmemd_src/etmemd_scan.c | 14 +++-
etmem/src/etmemd_src/etmemd_slide.c | 4 ++
10 files changed, 255 insertions(+), 48 deletions(-)
diff --git a/etmem/conf/slide_conf.yaml b/etmem/conf/slide_conf.yaml
index 511d657..f55c508 100644
--- a/etmem/conf/slide_conf.yaml
+++ b/etmem/conf/slide_conf.yaml
@@ -5,6 +5,8 @@ loop=1
interval=1
sleep=1
sysmem_threshold=50
+swapcache_high_wmark=10
+swapcache_low_wmark=6
[engine]
name=slide
diff --git a/etmem/inc/etmemd_inc/etmemd_common.h b/etmem/inc/etmemd_inc/etmemd_common.h
index 576d38a..ced606e 100644
--- a/etmem/inc/etmemd_inc/etmemd_common.h
+++ b/etmem/inc/etmemd_inc/etmemd_common.h
@@ -18,34 +18,47 @@
#include <stdio.h>
#include <stdbool.h>
+#include <sys/ioctl.h>
-#define PROC_PATH "/proc/"
-#define STATUS_FILE "/status"
-#define PROC_MEMINFO "meminfo"
-#define SWAPIN "SwapIN"
-#define VMRSS "VmRSS"
-#define VMSWAP "VmSwap"
-#define FILE_LINE_MAX_LEN 1024
-#define KEY_VALUE_MAX_LEN 64
-#define DECIMAL_RADIX 10
-#define ETMEMD_MAX_PARAMETER_NUM 6
-#define BYTE_TO_KB(s) ((s) >> 10)
-#define KB_TO_BYTE(s) ((s) << 10)
-#define CONVERT_GB_2_KB (1024 * 1024)
-
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+#define PROC_PATH "/proc/"
+#define STATUS_FILE "/status"
+#define PROC_MEMINFO "meminfo"
+#define SWAPIN "SwapIN"
+#define VMRSS "VmRSS"
+#define VMSWAP "VmSwap"
+
+#define FILE_LINE_MAX_LEN 1024
+#define KEY_VALUE_MAX_LEN 64
+#define DECIMAL_RADIX 10
+#define ETMEMD_MAX_PARAMETER_NUM 6
+
+#define BYTE_TO_KB(s) ((s) >> 10)
+#define KB_TO_BYTE(s) ((s) << 10)
+#define CONVERT_GB_2_KB (1024 * 1024)
+
+#define MAX_SWAPCACHE_WMARK_VALUE 100
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
/* in some system the max length of pid may be larger than 5, so we use 10 herr */
-#define PID_STR_MAX_LEN 10
+#define PID_STR_MAX_LEN 10
#define SWAP_THRESHOLD_MAX_LEN 10
-#define PIPE_FD_LEN 2
+#define PIPE_FD_LEN 2
+
+#define IDLE_SCAN_MAGIC 0x66
+#define IDLE_SCAN_ADD_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x0, unsigned int)
enum swap_type {
DONT_SWAP = 0,
DO_SWAP,
};
+struct ioctl_para {
+ unsigned long ioctl_cmd;
+ int ioctl_parameter;
+};
+
/*
* function: parse cmdline passed to etmemd server.
*
@@ -65,7 +78,8 @@ int get_unsigned_int_value(const char *val, unsigned int *value);
int get_unsigned_long_value(const char *val, unsigned long *value);
void etmemd_safe_free(void **ptr);
-FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const char *mode);
+FILE *etmemd_get_proc_file(const char *pid, const char *file, const char *mode);
+int etmemd_send_ioctl_cmd(FILE *fp, struct ioctl_para *request);
int get_keyword_and_value(const char *str, char *key, char *val);
unsigned long get_pagesize(void);
diff --git a/etmem/inc/etmemd_inc/etmemd_migrate.h b/etmem/inc/etmemd_inc/etmemd_migrate.h
index ef20bde..f8eb621 100644
--- a/etmem/inc/etmemd_inc/etmemd_migrate.h
+++ b/etmem/inc/etmemd_inc/etmemd_migrate.h
@@ -27,5 +27,6 @@
#define SWAP_ADDR_LEN 20
int etmemd_grade_migrate(const char* pid, const struct memory_grade *memory_grade);
+int etmemd_reclaim_swapcache(const struct task_pid *tk_pid);
unsigned long check_should_migrate(const struct task_pid *tk_pid);
#endif
diff --git a/etmem/inc/etmemd_inc/etmemd_project_exp.h b/etmem/inc/etmemd_inc/etmemd_project_exp.h
index fc3c85e..2fe8d90 100644
--- a/etmem/inc/etmemd_inc/etmemd_project_exp.h
+++ b/etmem/inc/etmemd_inc/etmemd_project_exp.h
@@ -43,7 +43,10 @@ struct project {
enum scan_type type;
void *scan_param;
int sysmem_threshold;
+ int swapcache_high_wmark;
+ int swapcache_low_wmark;
bool start;
+ bool wmark_set;
struct engine *engs;
SLIST_ENTRY(project) entry;
diff --git a/etmem/src/etmemd_src/etmemd_common.c b/etmem/src/etmemd_src/etmemd_common.c
index caa5826..bb72fd0 100644
--- a/etmem/src/etmemd_src/etmemd_common.c
+++ b/etmem/src/etmemd_src/etmemd_common.c
@@ -32,9 +32,6 @@
#include "etmemd_rpc.h"
#include "etmemd_log.h"
-#define IDLE_SCAN_MAGIC 0x66
-#define IDLE_SCAN_ADD_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x0, unsigned int)
-
static void usage(void)
{
printf("\nusage of etmemd:\n"
@@ -273,10 +270,32 @@ static char *etmemd_get_proc_file_str(const char *pid, const char *file)
return file_name;
}
-FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const char *mode)
+int etmemd_send_ioctl_cmd(FILE *fp, struct ioctl_para *request)
{
- char *file_name = NULL;
int fd = -1;
+
+ if (fp == NULL) {
+ etmemd_log(ETMEMD_LOG_ERR, "send ioctl cmd fail, fp is null\n");
+ return -1;
+ }
+
+ fd = fileno(fp);
+ if (fd < 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "send ioctl cmd fail, get fd fail\n");
+ return -1;
+ }
+
+ if (request == NULL || ioctl(fd, request->ioctl_cmd, &request->ioctl_parameter) != 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "send ioctl cmd fail, request is wrong\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+FILE *etmemd_get_proc_file(const char *pid, const char *file, const char *mode)
+{
+ char *file_name = NULL;
FILE *fp = NULL;
file_name = etmemd_get_proc_file_str(pid, file);
@@ -287,25 +306,8 @@ FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const c
fp = fopen(file_name, mode);
if (fp == NULL) {
etmemd_log(ETMEMD_LOG_ERR, "open file %s fail\n", file_name);
- goto free_file_name;
- }
-
- fd = fileno(fp);
- if (fd < 0) {
- etmemd_log(ETMEMD_LOG_ERR, "get fd of file %s fail\n", file_name);
- fclose(fp);
- fp = NULL;
- goto free_file_name;
- }
-
- if (flags != 0 && ioctl(fd, IDLE_SCAN_ADD_FLAGS, &flags) != 0) {
- etmemd_log(ETMEMD_LOG_ERR, "set idle flags for %s fail with %s\n", pid, strerror(errno));
- fclose(fp);
- fp = NULL;
- goto free_file_name;
}
-free_file_name:
free(file_name);
return fp;
}
@@ -453,7 +455,7 @@ int get_mem_from_proc_file(const char *pid, const char *file_name, unsigned long
unsigned long val;
int ret = -1;
- file = etmemd_get_proc_file(pid, file_name, 0, "r");
+ file = etmemd_get_proc_file(pid, file_name, "r");
if (file == NULL) {
etmemd_log(ETMEMD_LOG_ERR, "cannot open %s for pid %s\n", file_name, pid);
return ret;
diff --git a/etmem/src/etmemd_src/etmemd_cslide.c b/etmem/src/etmemd_src/etmemd_cslide.c
index b3d1637..cbaa2e8 100644
--- a/etmem/src/etmemd_src/etmemd_cslide.c
+++ b/etmem/src/etmemd_src/etmemd_cslide.c
@@ -1280,18 +1280,28 @@ static int cslide_scan_vmas(struct cslide_pid_params *params)
uint64_t i;
int fd;
struct cslide_task_params *task_params = params->task_params;
+ struct ioctl_para ioctl_para = {
+ .ioctl_cmd = IDLE_SCAN_ADD_FLAGS,
+ .ioctl_parameter = task_params->scan_flags,
+ };
if (snprintf_s(pid, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", params->pid) <= 0) {
etmemd_log(ETMEMD_LOG_ERR, "snpintf pid %u fail\n", params->pid);
return -1;
}
- scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, task_params->scan_flags, "r");
+ scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, "r");
if (scan_fp == NULL) {
etmemd_log(ETMEMD_LOG_ERR, "open %s file for pid %u fail\n", IDLE_SCAN_FILE, params->pid);
return -1;
}
+ if (task_params->scan_flags != 0 && etmemd_send_ioctl_cmd(scan_fp, &ioctl_para) != 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "etmemd send_ioctl_cmd %s file for pid %u fail\n", IDLE_SCAN_FILE, params->pid);
+ fclose(scan_fp);
+ return -1;
+ }
+
fd = fileno(scan_fp);
if (fd == -1) {
fclose(scan_fp);
diff --git a/etmem/src/etmemd_src/etmemd_migrate.c b/etmem/src/etmemd_src/etmemd_migrate.c
index 639d570..87bfde0 100644
--- a/etmem/src/etmemd_src/etmemd_migrate.c
+++ b/etmem/src/etmemd_src/etmemd_migrate.c
@@ -15,14 +15,24 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
#include "securec.h"
#include "etmemd.h"
#include "etmemd_migrate.h"
+#include "etmemd_project.h"
#include "etmemd_common.h"
#include "etmemd_slide.h"
#include "etmemd_log.h"
+#define RECLAIM_SWAPCACHE_MAGIC 0x77
+#define RECLAIM_SWAPCACHE_ON _IOW(RECLAIM_SWAPCACHE_MAGIC, 0x1, unsigned int)
+#define SET_SWAPCACHE_WMARK _IOW(RECLAIM_SWAPCACHE_MAGIC, 0x2, unsigned int)
+
static char *get_swap_string(struct page_refs **page_refs, int batchsize)
{
char *swap_str = NULL;
@@ -70,7 +80,7 @@ static int etmemd_migrate_mem(const char *pid, const char *grade_path, struct pa
return 0;
}
- fp = etmemd_get_proc_file(pid, grade_path, 0, "r+");
+ fp = etmemd_get_proc_file(pid, grade_path, "r+");
if (fp == NULL) {
etmemd_log(ETMEMD_LOG_ERR, "cannot open %s for pid %s\n", grade_path, pid);
return -1;
@@ -98,6 +108,107 @@ static int etmemd_migrate_mem(const char *pid, const char *grade_path, struct pa
return 0;
}
+static bool check_should_reclaim_swapcache(const struct task_pid *tk_pid)
+{
+ struct project *proj = tk_pid->tk->eng->proj;
+ unsigned long mem_total;
+ unsigned long swapcache_total;
+ int ret;
+
+ if (proj->swapcache_high_wmark == 0) {
+ return false;
+ }
+
+ ret = get_mem_from_proc_file(NULL, PROC_MEMINFO, &mem_total, "MemTotal");
+ if (ret != 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "get memtotal fail\n");
+ return false;
+ }
+
+ ret = get_mem_from_proc_file(NULL, PROC_MEMINFO, &swapcache_total, "SwapCached");
+ if (ret != 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "get swapcache_total fail\n");
+ return false;
+ }
+
+ if ((swapcache_total / proj->swapcache_high_wmark) <= (mem_total / MAX_SWAPCACHE_WMARK_VALUE)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int set_swapcache_wmark(const struct task_pid *tk_pid, const char *pid_str)
+{
+ int swapcache_wmark;
+ struct project *proj = tk_pid->tk->eng->proj;
+ FILE *fp = NULL;
+ struct ioctl_para ioctl_para = {
+ .ioctl_cmd = SET_SWAPCACHE_WMARK,
+ };
+
+ swapcache_wmark = (proj->swapcache_low_wmark & 0x00ff) | (proj->swapcache_high_wmark << 8 & 0xff00);
+ ioctl_para.ioctl_parameter = swapcache_wmark;
+
+ fp = etmemd_get_proc_file(pid_str, COLD_PAGE, "r+");
+ if (fp == NULL) {
+ etmemd_log(ETMEMD_LOG_ERR, "get proc file %s failed.\n", COLD_PAGE);
+ return -1;
+ }
+
+ if (etmemd_send_ioctl_cmd(fp, &ioctl_para) != 0) {
+ fclose(fp);
+ etmemd_log(ETMEMD_LOG_ERR, "set_swapcache_wmark for pid %u fail\n", tk_pid->pid);
+ return -1;
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+int etmemd_reclaim_swapcache(const struct task_pid *tk_pid)
+{
+ char pid_str[PID_STR_MAX_LEN] = {0};
+ FILE *fp = NULL;
+ struct ioctl_para ioctl_para = {
+ .ioctl_cmd = RECLAIM_SWAPCACHE_ON,
+ .ioctl_parameter = 0,
+ };
+
+ if (tk_pid == NULL) {
+ etmemd_log(ETMEMD_LOG_ERR, "tk_pid is null.\n");
+ return -1;
+ }
+
+ if (!check_should_reclaim_swapcache(tk_pid)) {
+ return 0;
+ }
+
+ if (snprintf_s(pid_str, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", tk_pid->pid) <= 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "snprintf pid fail %u", tk_pid->pid);
+ return -1;
+ }
+
+ if (!tk_pid->tk->eng->proj->wmark_set) {
+ set_swapcache_wmark(tk_pid, pid_str);
+ tk_pid->tk->eng->proj->wmark_set = true;
+ }
+
+ fp = etmemd_get_proc_file(pid_str, COLD_PAGE, "r+");
+ if (fp == NULL) {
+ etmemd_log(ETMEMD_LOG_ERR, "get proc file %s fail.\n", COLD_PAGE);
+ return -1;
+ }
+
+ if (etmemd_send_ioctl_cmd(fp, &ioctl_para) != 0) {
+ etmemd_log(ETMEMD_LOG_ERR, "etmemd_reclaim_swapcache fail\n");
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+ return 0;
+}
int etmemd_grade_migrate(const char *pid, const struct memory_grade *memory_grade)
{
diff --git a/etmem/src/etmemd_src/etmemd_project.c b/etmem/src/etmemd_src/etmemd_project.c
index 459e140..72d7335 100644
--- a/etmem/src/etmemd_src/etmemd_project.c
+++ b/etmem/src/etmemd_src/etmemd_project.c
@@ -639,19 +639,64 @@ static int fill_project_sysmem_threshold(void *obj, void *val)
int sysmem_threshold = parse_to_int(val);
if (sysmem_threshold < 0 || sysmem_threshold > MAX_SYSMEM_THRESHOLD_VALUE) {
- etmemd_log(ETMEMD_LOG_WARN, "invaild project sysmem_threshold value %d, it must between 0 and 100.\n",
- sysmem_threshold, MAX_SYSMEM_THRESHOLD_VALUE);
- sysmem_threshold = -1;
+ etmemd_log(ETMEMD_LOG_ERR, "invaild project sysmem_threshold value %d, it must between 0 and 100.\n",
+ sysmem_threshold);
+ return -1;
}
proj->sysmem_threshold = sysmem_threshold;
return 0;
}
+/* fill the project parameter: swapcache_low_wmark
+ * swapcache_low_wmark: [0, 100]. */
+static int fill_project_swapcache_low_wmark(void *obj, void *val)
+{
+ struct project *proj = (struct project *)obj;
+ int swapcache_low_wmark = parse_to_int(val);
+
+ if (swapcache_low_wmark < 0 || swapcache_low_wmark > MAX_SWAPCACHE_WMARK_VALUE) {
+ etmemd_log(ETMEMD_LOG_ERR, "invaild project swapcache_low_wmark value %d, it must between 0 and 100.\n",
+ swapcache_low_wmark);
+ return -1;
+ }
+
+ proj->swapcache_low_wmark = swapcache_low_wmark;
+ return 0;
+}
+
+/* fill the project parameter: swapcache_high_wmark
+ * swapcache_high_wmark: (0, 100]. */
+static int fill_project_swapcache_high_wmark(void *obj, void *val)
+{
+ struct project *proj = (struct project *)obj;
+ int swapcache_high_wmark = parse_to_int(val);
+
+ if (swapcache_high_wmark < 0 || swapcache_high_wmark > MAX_SWAPCACHE_WMARK_VALUE) {
+ etmemd_log(ETMEMD_LOG_ERR, "invaild project swapcache_high_wmark value %d, it must between 0 and 100.\n",
+ swapcache_high_wmark);
+ return -1;
+ }
+
+ proj->swapcache_high_wmark = swapcache_high_wmark;
+ return 0;
+}
+
+static bool check_swapcache_wmark_valid(struct project *proj)
+{
+ if (proj->swapcache_low_wmark > proj->swapcache_high_wmark) {
+ return false;
+ }
+
+ return true;
+}
+
static struct config_item g_project_config_items[] = {
{"name", STR_VAL, fill_project_name, false},
{"scan_type", STR_VAL, fill_project_scan_type, false},
{"sysmem_threshold", INT_VAL, fill_project_sysmem_threshold, true},
+ {"swapcache_high_wmark", INT_VAL, fill_project_swapcache_high_wmark, true},
+ {"swapcache_low_wmark", INT_VAL, fill_project_swapcache_low_wmark, true},
};
static void clear_project(struct project *proj)
@@ -675,6 +720,11 @@ static int project_fill_by_conf(GKeyFile *config, struct project *proj)
return -1;
}
+ if (!check_swapcache_wmark_valid(proj)) {
+ etmemd_log(ETMEMD_LOG_ERR, "swapcache wmark is not valid, low wmark: %d, high wmark: %d",
+ proj->swapcache_low_wmark, proj->swapcache_high_wmark);
+ return -1;
+ }
return 0;
}
diff --git a/etmem/src/etmemd_src/etmemd_scan.c b/etmem/src/etmemd_src/etmemd_scan.c
index 3ee018e..a1f8cdc 100644
--- a/etmem/src/etmemd_src/etmemd_scan.c
+++ b/etmem/src/etmemd_src/etmemd_scan.c
@@ -359,7 +359,7 @@ struct vmas *get_vmas_with_flags(const char *pid, char *vmflags_array[], int vmf
return NULL;
}
- fp = etmemd_get_proc_file(pid, maps_file, 0, "r");
+ fp = etmemd_get_proc_file(pid, maps_file, "r");
if (fp == NULL) {
etmemd_log(ETMEMD_LOG_ERR, "open %s file of %s fail\n", maps_file, pid);
free(ret_vmas);
@@ -680,13 +680,23 @@ int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **p
struct vma *vma = vmas->vma_list;
struct page_refs **tmp_page_refs = NULL;
struct walk_address walk_address = {0, 0, 0};
+ struct ioctl_para ioctl_para = {
+ .ioctl_cmd = IDLE_SCAN_ADD_FLAGS,
+ .ioctl_parameter = flags,
+ };
- scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, flags, "r");
+ scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, "r");
if (scan_fp == NULL) {
etmemd_log(ETMEMD_LOG_ERR, "open %s file fail\n", IDLE_SCAN_FILE);
return -1;
}
+ if (flags != 0 && etmemd_send_ioctl_cmd(scan_fp, &ioctl_para) != 0) {
+ fclose(scan_fp);
+ etmemd_log(ETMEMD_LOG_ERR, "etmemd_send_ioctl_cmd %s file for pid %s fail\n", IDLE_SCAN_FILE, pid);
+ return -1;
+ }
+
fd = fileno(scan_fp);
if (fd == -1) {
etmemd_log(ETMEMD_LOG_ERR, "fileno file fail\n");
diff --git a/etmem/src/etmemd_src/etmemd_slide.c b/etmem/src/etmemd_src/etmemd_slide.c
index cbc4b17..c478fbd 100644
--- a/etmem/src/etmemd_src/etmemd_slide.c
+++ b/etmem/src/etmemd_src/etmemd_slide.c
@@ -256,6 +256,10 @@ scan_out:
etmemd_log(ETMEMD_LOG_DEBUG, "slide migrate for pid %u fail\n", tk_pid->pid);
}
+ if (etmemd_reclaim_swapcache(tk_pid) != 0) {
+ etmemd_log(ETMEMD_LOG_DEBUG, "etmemd_reclaim_swapcache pid %u fail\n", tk_pid->pid);
+ }
+
exit:
/* clean memory_grade here */
pthread_cleanup_pop(1);
--
1.8.3.1