From d505503f276dd1efbd0d738e115024ab3b58aed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sat, 27 Aug 2022 14:29:37 +0200 Subject: [PATCH 1/7] initial usage of PSI (Pressure Stall Information) in memnotify --- modules/mempressure.c | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/modules/mempressure.c b/modules/mempressure.c index 5488b8b..bb58512 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -427,6 +428,134 @@ mempressure_cgroup_quit(void) } } +/** Eventfd for receiving notifications PSI memory changes */ +static int mempressure_psi_event_fd = -1; +static int mempressure_psi_warning_fd = -1; +static int mempressure_psi_critical_fd = -1; +static guint mempressure_psi_warn_event_id = 0; +static guint mempressure_psi_crit_event_id = 0; + +#define PSI_MEMORY_PATH "/proc/pressure/memory" + +/** Input watch callback for cgroup memory threshold crossings + */ +static gboolean +mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) +{ + (void)chn; + (void)aptr; + + gboolean ret = G_SOURCE_REMOVE; + + if( cnd & ~G_IO_PRI ) { + mce_log(LL_ERR, "unexpected input watch condition"); + goto EXIT; + } + if( aptr == NULL ) { + mce_log(LL_ERR, "null watch argument"); + goto EXIT; + } + + int fd = *((int*)aptr); + + if (fd == mempressure_psi_warning_fd) { + ret = G_SOURCE_CONTINUE; + mce_log(LL_INFO, "warning PSI change"); + } else if (fd == mempressure_psi_critical_fd) { + ret = G_SOURCE_CONTINUE; + mce_log(LL_INFO, "critical PSI change"); + } else { + mce_log(LL_CRIT, "unknown fd in iowatch callback"); + } + +EXIT: + + if( ret == G_SOURCE_REMOVE && + (mempressure_psi_warn_event_id || mempressure_psi_crit_event_id) ){ + mempressure_psi_warn_event_id = 0; + mempressure_psi_crit_event_id = 0; + mce_log(LL_CRIT, "disabling eventfd iowatch"); + } + + return ret; +} + +static void +mempressure_psi_quit(void) +{ + // TODO +} + +static bool +mempressure_psi_init(void) +{ + bool res = false; + + /* Get file descriptors */ + mce_log(LL_DEBUG, "create eventfd"); + if( (mempressure_psi_event_fd = eventfd(0, 0)) == -1 ) { + mce_log(LL_ERR, "create eventfd: %m"); + goto EXIT; + } + + /* Get file descriptors */ + mce_log(LL_DEBUG, "open %s for warning threshold", PSI_MEMORY_PATH); + if( (mempressure_psi_warning_fd = open(PSI_MEMORY_PATH, O_RDWR | O_NONBLOCK)) == -1 ) { + mce_log(LL_ERR, "%s: open: %m", PSI_MEMORY_PATH); + goto EXIT; + } + + mce_log(LL_DEBUG, "open %s for critical threshold", PSI_MEMORY_PATH); + if( (mempressure_psi_critical_fd = open(PSI_MEMORY_PATH, O_RDWR | O_NONBLOCK)) == -1 ) { + mce_log(LL_ERR, "%s: open: %m", PSI_MEMORY_PATH); + goto EXIT; + } + + // setup thresholds + // TODO: configurable + const char warning_threshold[] = "some 100000 1000000"; // 100 ms stall (some process) in one-second window + const char critical_threshold[] = "full 150000 1000000"; // 150 ms stall (all processes) in one-second window + + if (write(mempressure_psi_warning_fd, warning_threshold, strlen(warning_threshold) + 1) < 0) { + mce_log(LL_ERR, "%s: write: %m", PSI_MEMORY_PATH); + goto EXIT; + } + + if (write(mempressure_psi_critical_fd, critical_threshold, strlen(critical_threshold) + 1) < 0) { + mce_log(LL_ERR, "%s: write: %m", PSI_MEMORY_PATH); + goto EXIT; + } + + /* Setup notification iowatch */ + mce_log(LL_DEBUG, "add warning fd iowatch"); + mempressure_psi_warn_event_id = + mempressure_iowatch_add(mempressure_psi_warning_fd, false, G_IO_PRI, + mempressure_psi_event_cb, &mempressure_psi_warning_fd); + if( !mempressure_psi_warn_event_id ) { + mce_log(LL_ERR, "failed to add warning fd iowatch"); + goto EXIT; + } + + mce_log(LL_DEBUG, "add critical fd iowatch"); + mempressure_psi_crit_event_id = + mempressure_iowatch_add(mempressure_psi_critical_fd, false, G_IO_PRI, + mempressure_psi_event_cb, &mempressure_psi_critical_fd); + if( !mempressure_psi_crit_event_id ) { + mce_log(LL_ERR, "failed to add critical fd iowatch"); + goto EXIT; + } + + res = true; + +EXIT: + + // all or nothing + if( !res ) + mempressure_psi_quit(); + + return res; +} + /** Start cgroup memory tracking */ static bool @@ -688,6 +817,9 @@ mempressure_plugin_init(void) if( !mempressure_cgroup_init() ) goto EXIT; + if ( !mempressure_psi_init() ) + goto EXIT; + success = true; EXIT: From 0cb44a51c38dfe0a8f0b5366e0de735da6bdba17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sat, 27 Aug 2022 16:22:19 +0200 Subject: [PATCH 2/7] timeout of mempressure events --- modules/mempressure.c | 57 +++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/modules/mempressure.c b/modules/mempressure.c index bb58512..5f6997b 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -34,6 +34,7 @@ #include #include +#include /* Paths to relevant cgroup data/control files */ #define CGROUP_MEMORY_DIRECTORY "/sys/fs/cgroup/memory" @@ -428,16 +429,39 @@ mempressure_cgroup_quit(void) } } -/** Eventfd for receiving notifications PSI memory changes */ -static int mempressure_psi_event_fd = -1; static int mempressure_psi_warning_fd = -1; static int mempressure_psi_critical_fd = -1; static guint mempressure_psi_warn_event_id = 0; static guint mempressure_psi_crit_event_id = 0; +static guint mempressure_psi_warn_timeout = 0; +static guint mempressure_psi_crit_timeout = 0; #define PSI_MEMORY_PATH "/proc/pressure/memory" -/** Input watch callback for cgroup memory threshold crossings +static gboolean +mempressure_psi_timeout_cb(gpointer user_data) +{ + if( user_data == NULL ) { + mce_log(LL_ERR, "null timeout argument"); + goto EXIT; + } + + int fd = *((int*)user_data); + if (fd == mempressure_psi_warning_fd) { + mce_log(LL_INFO, "PSI warning event timeout"); + mempressure_psi_warn_timeout = 0; + } else if (fd == mempressure_psi_critical_fd) { + mce_log(LL_INFO, "PSI critical event timeout"); + mempressure_psi_crit_timeout = 0; + } else { + mce_log(LL_CRIT, "unknown fd in timeout callback"); + } + +EXIT: + return G_SOURCE_REMOVE; +} + +/** Input watch callback for PSI events */ static gboolean mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) @@ -458,12 +482,22 @@ mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) int fd = *((int*)aptr); - if (fd == mempressure_psi_warning_fd) { - ret = G_SOURCE_CONTINUE; - mce_log(LL_INFO, "warning PSI change"); - } else if (fd == mempressure_psi_critical_fd) { + if (fd == mempressure_psi_warning_fd || fd == mempressure_psi_critical_fd) { + if (fd == mempressure_psi_warning_fd) { + mce_log(LL_INFO, "warning PSI event"); + if (mempressure_psi_warn_timeout != 0) { + g_source_remove(mempressure_psi_warn_timeout); + } + mempressure_psi_warn_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); + } else { + assert(fd == mempressure_psi_critical_fd); + mce_log(LL_INFO, "critical PSI event"); + if (mempressure_psi_crit_timeout != 0) { + g_source_remove(mempressure_psi_crit_timeout); + } + mempressure_psi_crit_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); + } ret = G_SOURCE_CONTINUE; - mce_log(LL_INFO, "critical PSI change"); } else { mce_log(LL_CRIT, "unknown fd in iowatch callback"); } @@ -491,13 +525,6 @@ mempressure_psi_init(void) { bool res = false; - /* Get file descriptors */ - mce_log(LL_DEBUG, "create eventfd"); - if( (mempressure_psi_event_fd = eventfd(0, 0)) == -1 ) { - mce_log(LL_ERR, "create eventfd: %m"); - goto EXIT; - } - /* Get file descriptors */ mce_log(LL_DEBUG, "open %s for warning threshold", PSI_MEMORY_PATH); if( (mempressure_psi_warning_fd = open(PSI_MEMORY_PATH, O_RDWR | O_NONBLOCK)) == -1 ) { From bde212e6c73c0d55b0a789cf1ee09752f5dbaf38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sat, 27 Aug 2022 16:43:00 +0200 Subject: [PATCH 3/7] update memnotify level --- modules/mempressure.c | 60 +++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/modules/mempressure.c b/modules/mempressure.c index 5f6997b..50dd3bb 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -438,6 +438,28 @@ static guint mempressure_psi_crit_timeout = 0; #define PSI_MEMORY_PATH "/proc/pressure/memory" +static void +mempressure_psi_update_level(void) +{ + memnotify_level_t prev = mempressure_level; + + if ( mempressure_psi_crit_timeout != 0 ) { + mempressure_level = MEMNOTIFY_LEVEL_CRITICAL; + } else if ( mempressure_psi_warn_timeout != 0 ) { + mempressure_level = MEMNOTIFY_LEVEL_WARNING; + } else { + mempressure_level = MEMNOTIFY_LEVEL_NORMAL; + } + if ( prev != mempressure_level ) { + mce_log(LL_WARN, "mempressure_level: %s -> %s", + memnotify_level_repr(prev), + memnotify_level_repr(mempressure_level)); + + datapipe_exec_full(&memnotify_level_pipe, + GINT_TO_POINTER(mempressure_level)); + } +} + static gboolean mempressure_psi_timeout_cb(gpointer user_data) { @@ -455,8 +477,11 @@ mempressure_psi_timeout_cb(gpointer user_data) mempressure_psi_crit_timeout = 0; } else { mce_log(LL_CRIT, "unknown fd in timeout callback"); + goto EXIT; } + mempressure_psi_update_level(); + EXIT: return G_SOURCE_REMOVE; } @@ -482,25 +507,27 @@ mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) int fd = *((int*)aptr); - if (fd == mempressure_psi_warning_fd || fd == mempressure_psi_critical_fd) { - if (fd == mempressure_psi_warning_fd) { - mce_log(LL_INFO, "warning PSI event"); - if (mempressure_psi_warn_timeout != 0) { - g_source_remove(mempressure_psi_warn_timeout); - } - mempressure_psi_warn_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); - } else { - assert(fd == mempressure_psi_critical_fd); - mce_log(LL_INFO, "critical PSI event"); - if (mempressure_psi_crit_timeout != 0) { - g_source_remove(mempressure_psi_crit_timeout); - } - mempressure_psi_crit_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); + if (fd != mempressure_psi_warning_fd && fd != mempressure_psi_critical_fd) { + mce_log(LL_CRIT, "unknown fd in iowatch callback"); + goto EXIT; + } + + if (fd == mempressure_psi_warning_fd) { + mce_log(LL_INFO, "warning PSI event"); + if (mempressure_psi_warn_timeout != 0) { + g_source_remove(mempressure_psi_warn_timeout); } - ret = G_SOURCE_CONTINUE; + mempressure_psi_warn_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); } else { - mce_log(LL_CRIT, "unknown fd in iowatch callback"); + assert(fd == mempressure_psi_critical_fd); + mce_log(LL_INFO, "critical PSI event"); + if (mempressure_psi_crit_timeout != 0) { + g_source_remove(mempressure_psi_crit_timeout); + } + mempressure_psi_crit_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); } + mempressure_psi_update_level(); + ret = G_SOURCE_CONTINUE; EXIT: @@ -573,6 +600,7 @@ mempressure_psi_init(void) } res = true; + mempressure_level = MEMNOTIFY_LEVEL_NORMAL; EXIT: From d9e9a1706b8cde91dda64d37b78c0055a8af2314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sat, 27 Aug 2022 16:43:16 +0200 Subject: [PATCH 4/7] PSI cleanup --- modules/mempressure.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/modules/mempressure.c b/modules/mempressure.c index 50dd3bb..233699f 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -544,7 +544,34 @@ mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) static void mempressure_psi_quit(void) { - // TODO + if ( mempressure_psi_warn_timeout != 0 ) { + g_source_remove(mempressure_psi_warn_timeout); + } + if ( mempressure_psi_crit_timeout != 0 ) { + g_source_remove(mempressure_psi_crit_timeout); + } + if( mempressure_psi_warn_event_id ) { + mce_log(LL_DEBUG, "remove warnong eventfd iowatch"); + g_source_remove(mempressure_psi_warn_event_id), + mempressure_psi_warn_event_id = 0; + } + if( mempressure_psi_crit_event_id ) { + mce_log(LL_DEBUG, "remove critical eventfd iowatch"); + g_source_remove(mempressure_psi_crit_event_id), + mempressure_psi_crit_event_id = 0; + } + if ( mempressure_psi_warning_fd ) { + if ( close( mempressure_psi_warning_fd ) < 0) { + mce_log(LL_ERR, "close failed"); + } + mempressure_psi_warning_fd = 0; + } + if ( mempressure_psi_critical_fd ) { + if ( close( mempressure_psi_critical_fd ) < 0) { + mce_log(LL_ERR, "close failed"); + } + mempressure_psi_critical_fd = 0; + } } static bool From 6b4fa250d1b0868b7a49cac69f1d29670463176b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sat, 27 Aug 2022 16:45:44 +0200 Subject: [PATCH 5/7] log events on debug --- modules/mempressure.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/mempressure.c b/modules/mempressure.c index 233699f..341489a 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -469,11 +469,11 @@ mempressure_psi_timeout_cb(gpointer user_data) } int fd = *((int*)user_data); - if (fd == mempressure_psi_warning_fd) { - mce_log(LL_INFO, "PSI warning event timeout"); + if ( fd == mempressure_psi_warning_fd ) { + mce_log(LL_DEBUG, "PSI warning event timeout"); mempressure_psi_warn_timeout = 0; - } else if (fd == mempressure_psi_critical_fd) { - mce_log(LL_INFO, "PSI critical event timeout"); + } else if ( fd == mempressure_psi_critical_fd ) { + mce_log(LL_DEBUG, "PSI critical event timeout"); mempressure_psi_crit_timeout = 0; } else { mce_log(LL_CRIT, "unknown fd in timeout callback"); @@ -513,14 +513,14 @@ mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) } if (fd == mempressure_psi_warning_fd) { - mce_log(LL_INFO, "warning PSI event"); + mce_log(LL_DEBUG, "warning PSI event"); if (mempressure_psi_warn_timeout != 0) { g_source_remove(mempressure_psi_warn_timeout); } mempressure_psi_warn_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); } else { assert(fd == mempressure_psi_critical_fd); - mce_log(LL_INFO, "critical PSI event"); + mce_log(LL_DEBUG, "critical PSI event"); if (mempressure_psi_crit_timeout != 0) { g_source_remove(mempressure_psi_crit_timeout); } From cbc18d1d0023e38d2656889bd4754a6d7c3515ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sun, 28 Aug 2022 01:23:01 +0200 Subject: [PATCH 6/7] mempressure PSI configuration --- Makefile | 1 + builtin-gconf.c | 26 ++ modules/mempressure.c | 818 ++++++++++++++++++------------------------ modules/mempressure.h | 58 +++ 4 files changed, 440 insertions(+), 463 deletions(-) create mode 100644 modules/mempressure.h diff --git a/Makefile b/Makefile index ce133e6..3007778 100644 --- a/Makefile +++ b/Makefile @@ -643,6 +643,7 @@ NORMALIZE_USES_SPC =\ modules/memnotify.c\ modules/memnotify.h\ modules/mempressure.c\ + modules/mempressure.h\ modules/packagekit.c\ modules/powersavemode.h\ modules/proximity.c\ diff --git a/builtin-gconf.c b/builtin-gconf.c index a5df1d0..d19cb5f 100644 --- a/builtin-gconf.c +++ b/builtin-gconf.c @@ -43,6 +43,7 @@ #include "event-input.h" #include "modules/memnotify.h" +#include "modules/mempressure.h" #include "modules/display.h" #include "modules/proximity.h" #include "modules/powersavemode.h" @@ -1873,6 +1874,31 @@ static const setting_t gconf_defaults[] = .type = "i", .def = G_STRINGIFY(MCE_DEFAULT_MEMNOTIFY_CRITICAL_ACTIVE) }, + { + .key = MCE_SETTING_MEMPRESSURE_WINDOW, + .type = "i", + .def = G_STRINGIFY(MCE_DEFAULT_MEMPRESSURE_WINDOW) + }, + { + .key = MCE_SETTING_MEMPRESSURE_WARNING_STALL, + .type = "i", + .def = G_STRINGIFY(MCE_DEFAULT_MEMPRESSURE_WARNING_STALL) + }, + { + .key = MCE_SETTING_MEMPRESSURE_WARNING_TYPE, + .type = "s", + .def = MCE_DEFAULT_MEMPRESSURE_WARNING_TYPE + }, + { + .key = MCE_SETTING_MEMPRESSURE_CRITICAL_STALL, + .type = "i", + .def = G_STRINGIFY(MCE_DEFAULT_MEMPRESSURE_CRITICAL_STALL) + }, + { + .key = MCE_SETTING_MEMPRESSURE_CRITICAL_TYPE, + .type = "s", + .def = MCE_DEFAULT_MEMPRESSURE_CRITICAL_TYPE + }, { .key = MCE_SETTING_TK_EXCEPT_LEN_CALL_IN, .type = "i", diff --git a/modules/mempressure.c b/modules/mempressure.c index 341489a..2fac8aa 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -19,7 +19,7 @@ * License along with mce. If not, see . */ -#include "memnotify.h" +#include "mempressure.h" #include "../mce.h" #include "../mce-log.h" @@ -36,31 +36,23 @@ #include #include -/* Paths to relevant cgroup data/control files */ -#define CGROUP_MEMORY_DIRECTORY "/sys/fs/cgroup/memory" -#define CGROUP_DATA_PATH CGROUP_MEMORY_DIRECTORY "/memory.usage_in_bytes" -#define CGROUP_CTRL_PATH CGROUP_MEMORY_DIRECTORY "/cgroup.event_control" +// /* Paths to relevant cgroup data/control files */ +// #define CGROUP_MEMORY_DIRECTORY "/sys/fs/cgroup/memory" +// #define CGROUP_DATA_PATH CGROUP_MEMORY_DIRECTORY "/memory.usage_in_bytes" +// #define CGROUP_CTRL_PATH CGROUP_MEMORY_DIRECTORY "/cgroup.event_control" -/* RAM page size in bytes - * - * Configuration is defined in terms of (memnotify style) page counts. - * - * Conversion to/from byte counts used in cgroups interface are done via: - * - mempressure_bytes_to_pages() - * - mempressure_pages_to_bytes() - */ -#define PAGE_SIZE ((unsigned long)sysconf(_SC_PAGESIZE)) +#define PSI_MEMORY_PATH "/proc/pressure/memory" /* ========================================================================= * * Types * ========================================================================= */ /** Structure for holding for /dev/mempressure compatible limit data */ -typedef struct -{ - /** Estimate of number of non-discardable RAM pages */ - gint mnl_used; -} mempressure_limit_t; +// typedef struct +// { +// /** Estimate of number of non-discardable RAM pages */ +// gint mnl_used; +// } mempressure_limit_t; /* ========================================================================= * * Prototypes @@ -70,38 +62,29 @@ typedef struct * UTILITY * ------------------------------------------------------------------------- */ -static int mempressure_bytes_to_pages(uint64_t bytes); -static uint64_t mempressure_pages_to_bytes(int pages); +// static int mempressure_bytes_to_pages(uint64_t bytes); +// static uint64_t mempressure_pages_to_bytes(int pages); static guint mempressure_iowatch_add (int fd, bool close_on_unref, GIOCondition cnd, GIOFunc io_cb, gpointer aptr); - -/* ------------------------------------------------------------------------- * - * MEMPRESSURE_LIMIT - * ------------------------------------------------------------------------- */ - -static void mempressure_limit_clear (mempressure_limit_t *self); -static bool mempressure_limit_is_valid(const mempressure_limit_t *self); -static int mempressure_limit_repr (const mempressure_limit_t *self, char *data, size_t size); -static bool mempressure_limit_parse (mempressure_limit_t *self, const char *data); -static bool mempressure_limit_exceeded(const mempressure_limit_t *self, const mempressure_limit_t *status); +static bool mempressure_streq (const char *s1, const char *s2); /* ------------------------------------------------------------------------- * * MEMPRESSURE_STATUS * ------------------------------------------------------------------------- */ -static memnotify_level_t mempressure_status_evaluate_level(void); -static bool mempressure_status_update_level (void); -static void mempressure_status_show_triggers (void); +// static memnotify_level_t mempressure_status_evaluate_level(void); +// static bool mempressure_status_update_level (void); +// static void mempressure_status_show_triggers (void); /* ------------------------------------------------------------------------- * * MEMPRESSURE_CGROUP * ------------------------------------------------------------------------- */ -static bool mempressure_cgroup_is_available (void); -static gboolean mempressure_cgroup_event_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr); -static void mempressure_cgroup_quit (void); -static bool mempressure_cgroup_init (void); -static void mempressure_cgroup_update_thresholds(void); -static bool mempressure_cgroup_update_status (void); +// static bool mempressure_cgroup_is_available (void); +// static gboolean mempressure_cgroup_event_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr); +// static void mempressure_cgroup_quit (void); +// static bool mempressure_cgroup_init (void); +// static bool mempressure_cgroup_update_status (void); +// /* ------------------------------------------------------------------------- * * MEMPRESSURE_SETTING @@ -129,21 +112,22 @@ void g_module_unload (GModule *module); * UTILITY * ========================================================================= */ -/* Convert kernel reported byte count to page count used in configuration - */ -static int mempressure_bytes_to_pages(uint64_t bytes) -{ - return (int)(bytes / PAGE_SIZE); -} - -/* Convert configuration page count to bytes for use in kernel interface - */ -static uint64_t mempressure_pages_to_bytes(int pages) -{ - if( pages < 0 ) - pages = 0; - return PAGE_SIZE * (uint64_t)pages; -} +// /* Convert kernel reported byte count to page count used in configuration +// */ +// static int mempressure_bytes_to_pages(uint64_t bytes) +// { +// return (int)(bytes / PAGE_SIZE); +// } +// +// /* Convert configuration page count to bytes for use in kernel interface +// */ +// static uint64_t mempressure_pages_to_bytes(int pages) +// { +// if( pages < 0 ) +// pages = 0; +// return PAGE_SIZE * (uint64_t)pages; +// } +// /** Add a glib I/O notification for a file descriptor */ @@ -172,262 +156,224 @@ mempressure_iowatch_add(int fd, bool close_on_unref, return wid; } -/* ========================================================================= * - * MEMPRESSURE_LIMIT - * ========================================================================= */ - -/** Reset limit object values - */ -static void -mempressure_limit_clear(mempressure_limit_t *self) -{ - self->mnl_used = 0; -} - -/** Limit validity predicate - */ -static bool -mempressure_limit_is_valid(const mempressure_limit_t *self) -{ - return self->mnl_used > 0; -} - -/** Convert limit object values to /dev/mempressure compatible ascii form +/* Null tolerant string equality predicate + * + * @param s1 string + * @param s2 string + * + * @return true if both s1 and s2 are null or same string, false otherwise */ -static int -mempressure_limit_repr(const mempressure_limit_t *self, char *data, size_t size) +static bool mempressure_streq(const char *s1, const char *s2) { - int res = snprintf(data, size, "used %d", self->mnl_used); - return res; + return (s1 && s2) ? !strcmp(s1, s2) : (s1 == s2); } -/** Parse limit object from /sys/fs/cgroup/memory/memory.usage_in_bytes format - */ -static bool -mempressure_limit_parse(mempressure_limit_t *self, const char *data) -{ - char *end = 0; - uint64_t val = strtoull(data, &end, 10); - bool res = end > data && *end == 0; - - if( !res ) - mce_log(LL_ERR, "parse error: '%s' is not a number", data); - else - self->mnl_used = mempressure_bytes_to_pages(val); - - return res; -} +/* ========================================================================= * + * MEMPRESSURE_LIMIT + * ========================================================================= */ -/** Check if limit object values are exceeded by given state data - */ -static bool -mempressure_limit_exceeded(const mempressure_limit_t *self, - const mempressure_limit_t *status) -{ - return (mempressure_limit_is_valid(self) && - self->mnl_used <= status->mnl_used); -} +// /** Reset limit object values +// */ +// static void +// mempressure_limit_clear(mempressure_limit_t *self) +// { +// self->mnl_used = 0; +// } +// +// /** Limit validity predicate +// */ +// static bool +// mempressure_limit_is_valid(const mempressure_limit_t *self) +// { +// return self->mnl_used > 0; +// } +// +// /** Convert limit object values to /dev/mempressure compatible ascii form +// */ +// static int +// mempressure_limit_repr(const mempressure_limit_t *self, char *data, size_t size) +// { +// int res = snprintf(data, size, "used %d", self->mnl_used); +// return res; +// } +// +// /** Parse limit object from /sys/fs/cgroup/memory/memory.usage_in_bytes format +// */ +// static bool +// mempressure_limit_parse(mempressure_limit_t *self, const char *data) +// { +// char *end = 0; +// uint64_t val = strtoull(data, &end, 10); +// bool res = end > data && *end == 0; +// +// if( !res ) +// mce_log(LL_ERR, "parse error: '%s' is not a number", data); +// else +// self->mnl_used = mempressure_bytes_to_pages(val); +// +// return res; +// } +// +// /** Check if limit object values are exceeded by given state data +// */ +// static bool +// mempressure_limit_exceeded(const mempressure_limit_t *self, +// const mempressure_limit_t *status) +// { +// return (mempressure_limit_is_valid(self) && +// self->mnl_used <= status->mnl_used); +// } /* ========================================================================= * * MEMPRESSURE_STATUS * ========================================================================= */ -/** Configuration limits for normal/warning/critical levels */ -static mempressure_limit_t mempressure_limit[] = -{ - [MEMNOTIFY_LEVEL_NORMAL] = { - .mnl_used = 0, - }, - [MEMNOTIFY_LEVEL_WARNING] = { - // values come from config - disabled by default - .mnl_used = 0, - }, - [MEMNOTIFY_LEVEL_CRITICAL] = { - // values come from config - disabled by default - .mnl_used = 0, - }, -}; - -/** Cached status read from kernel device */ -static mempressure_limit_t mempressure_status = -{ - .mnl_used = 0, -}; +/** Configuration */ +static gint mempressure_window = MCE_DEFAULT_MEMPRESSURE_WINDOW; +static gint mempressure_warning_stall = MCE_DEFAULT_MEMPRESSURE_WARNING_STALL; +static char* mempressure_warning_type = NULL; +static gint mempressure_critical_stall = MCE_DEFAULT_MEMPRESSURE_CRITICAL_STALL; +static char* mempressure_critical_type = NULL; /** Cached memory use level */ static memnotify_level_t mempressure_level = MEMNOTIFY_LEVEL_UNKNOWN; -/** Check current memory status against triggering levels - */ -static memnotify_level_t -mempressure_status_evaluate_level(void) -{ - memnotify_level_t res = MEMNOTIFY_LEVEL_UNKNOWN; - - if( mempressure_limit_is_valid(&mempressure_status) ) { - res = MEMNOTIFY_LEVEL_NORMAL; - - for( memnotify_level_t lev = MEMNOTIFY_LEVEL_NORMAL + 1; - lev < G_N_ELEMENTS(mempressure_limit); ++lev ) { - if( mempressure_limit_exceeded(mempressure_limit+lev, &mempressure_status) ) - res = lev; - } - } - - return res; -} - /** Re-evaluate memory use level and broadcast changes via datapipe */ -static bool -mempressure_status_update_level(void) -{ - memnotify_level_t prev = mempressure_level; - mempressure_level = mempressure_status_evaluate_level(); - - if( mempressure_level == prev ) - goto EXIT; - - mce_log(LL_WARN, "mempressure_level: %s -> %s", - memnotify_level_repr(prev), - memnotify_level_repr(mempressure_level)); - - datapipe_exec_full(&memnotify_level_pipe, - GINT_TO_POINTER(mempressure_level)); - -EXIT: - - return mempressure_level != MEMNOTIFY_LEVEL_UNKNOWN; -} - -/** Log current memory level configuration for debugging purposes - */ -static void -mempressure_status_show_triggers(void) -{ - if( mce_log_p(LL_DEBUG) ) { - for( size_t i = 0; i < G_N_ELEMENTS(mempressure_limit); ++i ) { - char tmp[256]; - mempressure_limit_repr(mempressure_limit+i, tmp, sizeof tmp); - mce_log(LL_DEBUG, "%s: %s", memnotify_level_repr(i), tmp); - } - } -} +// static bool +// mempressure_status_update_level(void) +// { +// memnotify_level_t prev = mempressure_level; +// mempressure_level = mempressure_status_evaluate_level(); +// +// if( mempressure_level == prev ) +// goto EXIT; +// +// mce_log(LL_WARN, "mempressure_level: %s -> %s", +// memnotify_level_repr(prev), +// memnotify_level_repr(mempressure_level)); +// +// datapipe_exec_full(&memnotify_level_pipe, +// GINT_TO_POINTER(mempressure_level)); +// +// EXIT: +// +// return mempressure_level != MEMNOTIFY_LEVEL_UNKNOWN; +// } /* ========================================================================= * * MEMPRESSURE_CGROUP * ========================================================================= */ /** File descriptor for CGROUP_DATA_PATH */ -static int mempressure_cgroup_data_fd = -1; +// static int mempressure_cgroup_data_fd = -1; /** File descriptor for CGROUP_CTRL_PATH */ -static int mempressure_cgroup_ctrl_fd = -1; +// static int mempressure_cgroup_ctrl_fd = -1; /** Eventfd for receiving notifications about threshold crossings */ -static int mempressure_cgroup_event_fd = -1; +// static int mempressure_cgroup_event_fd = -1; /** I/O watch for mempressure_cgroup_event_fd */ -static guint mempressure_cgroup_event_id = 0; +// static guint mempressure_cgroup_event_id = 0; -/** Probe if the required cgroup sysfs files are present +/** Probe if the required PSI sysfs files are present */ static bool -mempressure_cgroup_is_available(void) +mempressure_psi_is_available(void) { - return (access(CGROUP_DATA_PATH, R_OK) == 0 && - access(CGROUP_CTRL_PATH, W_OK) == 0); + return access(PSI_MEMORY_PATH, R_OK) == 0; } /** Input watch callback for cgroup memory threshold crossings */ -static gboolean -mempressure_cgroup_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) -{ - (void) chn; - (void) aptr; - - gboolean ret = G_SOURCE_REMOVE; - - if( !mempressure_cgroup_event_id ) - goto EXIT; - - if( mempressure_cgroup_event_fd == -1 ) - goto EXIT; - - if( mempressure_cgroup_data_fd == -1 ) - goto EXIT; - - mce_log(LL_DEBUG, "eventfd iowatch notify"); - - if( cnd & ~G_IO_IN ) { - mce_log(LL_ERR, "unexpected input watch condition"); - goto EXIT; - } - - uint64_t count = 0; - ssize_t rc = read(mempressure_cgroup_event_fd, &count, sizeof count); - - if( rc == 0 ) { - mce_log(LL_ERR, "eventfd eof"); - goto EXIT; - } - - if( rc == -1 ) { - if( errno == EINTR || errno == EAGAIN ) - ret = G_SOURCE_CONTINUE; - else - mce_log(LL_ERR, "eventfd error: %m"); - goto EXIT; - } - - if( mempressure_cgroup_update_status() ) - ret = G_SOURCE_CONTINUE; - - /* Update level anyway -> if we disable iowatch due to - * read/parse errors, the level gets reset to 'unknown'. - */ - mempressure_status_update_level(); - -EXIT: - - if( ret == G_SOURCE_REMOVE && mempressure_cgroup_event_id ) { - mempressure_cgroup_event_id = 0; - mce_log(LL_CRIT, "disabling eventfd iowatch"); - } - - return ret; -} - -/** Stop cgroup memory tracking - */ -static void -mempressure_cgroup_quit(void) -{ - if( mempressure_cgroup_event_id ) { - mce_log(LL_DEBUG, "remove eventfd iowatch"); - g_source_remove(mempressure_cgroup_event_id), - mempressure_cgroup_event_id = 0; - } - - if( mempressure_cgroup_event_fd != -1 ) { - mce_log(LL_DEBUG, "close eventfd"); - close(mempressure_cgroup_event_fd), - mempressure_cgroup_event_fd = -1; - } - - if( mempressure_cgroup_ctrl_fd != -1 ) { - mce_log(LL_DEBUG, "close %s", CGROUP_CTRL_PATH); - close(mempressure_cgroup_ctrl_fd), - mempressure_cgroup_ctrl_fd = -1; - } - - if( mempressure_cgroup_data_fd != -1 ) { - mce_log(LL_DEBUG, "close %s", CGROUP_DATA_PATH); - close(mempressure_cgroup_data_fd), - mempressure_cgroup_data_fd = -1; - } -} +// static gboolean +// mempressure_cgroup_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) +// { +// (void) chn; +// (void) aptr; +// +// gboolean ret = G_SOURCE_REMOVE; +// +// if( !mempressure_cgroup_event_id ) +// goto EXIT; +// +// if( mempressure_cgroup_event_fd == -1 ) +// goto EXIT; +// +// if( mempressure_cgroup_data_fd == -1 ) +// goto EXIT; +// +// mce_log(LL_DEBUG, "eventfd iowatch notify"); +// +// if( cnd & ~G_IO_IN ) { +// mce_log(LL_ERR, "unexpected input watch condition"); +// goto EXIT; +// } +// +// uint64_t count = 0; +// ssize_t rc = read(mempressure_cgroup_event_fd, &count, sizeof count); +// +// if( rc == 0 ) { +// mce_log(LL_ERR, "eventfd eof"); +// goto EXIT; +// } +// +// if( rc == -1 ) { +// if( errno == EINTR || errno == EAGAIN ) +// ret = G_SOURCE_CONTINUE; +// else +// mce_log(LL_ERR, "eventfd error: %m"); +// goto EXIT; +// } +// +// if( mempressure_cgroup_update_status() ) +// ret = G_SOURCE_CONTINUE; +// +// /* Update level anyway -> if we disable iowatch due to +// * read/parse errors, the level gets reset to 'unknown'. +// */ +// mempressure_status_update_level(); +// +// EXIT: +// +// if( ret == G_SOURCE_REMOVE && mempressure_cgroup_event_id ) { +// mempressure_cgroup_event_id = 0; +// mce_log(LL_CRIT, "disabling eventfd iowatch"); +// } +// +// return ret; +// } +// +// /** Stop cgroup memory tracking +// */ +// static void +// mempressure_cgroup_quit(void) +// { +// if( mempressure_cgroup_event_id ) { +// mce_log(LL_DEBUG, "remove eventfd iowatch"); +// g_source_remove(mempressure_cgroup_event_id), +// mempressure_cgroup_event_id = 0; +// } +// +// if( mempressure_cgroup_event_fd != -1 ) { +// mce_log(LL_DEBUG, "close eventfd"); +// close(mempressure_cgroup_event_fd), +// mempressure_cgroup_event_fd = -1; +// } +// +// if( mempressure_cgroup_ctrl_fd != -1 ) { +// mce_log(LL_DEBUG, "close %s", CGROUP_CTRL_PATH); +// close(mempressure_cgroup_ctrl_fd), +// mempressure_cgroup_ctrl_fd = -1; +// } +// +// if( mempressure_cgroup_data_fd != -1 ) { +// mce_log(LL_DEBUG, "close %s", CGROUP_DATA_PATH); +// close(mempressure_cgroup_data_fd), +// mempressure_cgroup_data_fd = -1; +// } +// } static int mempressure_psi_warning_fd = -1; static int mempressure_psi_critical_fd = -1; @@ -436,8 +382,6 @@ static guint mempressure_psi_crit_event_id = 0; static guint mempressure_psi_warn_timeout = 0; static guint mempressure_psi_crit_timeout = 0; -#define PSI_MEMORY_PATH "/proc/pressure/memory" - static void mempressure_psi_update_level(void) { @@ -451,7 +395,7 @@ mempressure_psi_update_level(void) mempressure_level = MEMNOTIFY_LEVEL_NORMAL; } if ( prev != mempressure_level ) { - mce_log(LL_WARN, "mempressure_level: %s -> %s", + mce_log(LL_INFO, "mempressure_level: %s -> %s", memnotify_level_repr(prev), memnotify_level_repr(mempressure_level)); @@ -517,14 +461,16 @@ mempressure_psi_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) if (mempressure_psi_warn_timeout != 0) { g_source_remove(mempressure_psi_warn_timeout); } - mempressure_psi_warn_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); + mempressure_psi_warn_timeout = g_timeout_add((mempressure_window / 1000) * 2, + mempressure_psi_timeout_cb, aptr); } else { assert(fd == mempressure_psi_critical_fd); mce_log(LL_DEBUG, "critical PSI event"); if (mempressure_psi_crit_timeout != 0) { g_source_remove(mempressure_psi_crit_timeout); } - mempressure_psi_crit_timeout = g_timeout_add(2000, mempressure_psi_timeout_cb, aptr); + mempressure_psi_crit_timeout = g_timeout_add((mempressure_window / 1000) * 2, + mempressure_psi_timeout_cb, aptr); } mempressure_psi_update_level(); ret = G_SOURCE_CONTINUE; @@ -593,16 +539,25 @@ mempressure_psi_init(void) } // setup thresholds - // TODO: configurable - const char warning_threshold[] = "some 100000 1000000"; // 100 ms stall (some process) in one-second window - const char critical_threshold[] = "full 150000 1000000"; // 150 ms stall (all processes) in one-second window + char buf[1024]; + snprintf(buf, sizeof buf, + "%s %d %d", + mempressure_warning_type, mempressure_warning_stall, mempressure_window); + + mce_log(LL_DEBUG, "warning threshold: %s", buf); - if (write(mempressure_psi_warning_fd, warning_threshold, strlen(warning_threshold) + 1) < 0) { + if (write(mempressure_psi_warning_fd, buf, strlen(buf) + 1) < 0) { mce_log(LL_ERR, "%s: write: %m", PSI_MEMORY_PATH); goto EXIT; } - if (write(mempressure_psi_critical_fd, critical_threshold, strlen(critical_threshold) + 1) < 0) { + snprintf(buf, sizeof buf, + "%s %d %d", + mempressure_critical_type, mempressure_critical_stall, mempressure_window); + + mce_log(LL_DEBUG, "critical threshold: %s", buf); + + if (write(mempressure_psi_critical_fd, buf, strlen(buf) + 1) < 0) { mce_log(LL_ERR, "%s: write: %m", PSI_MEMORY_PATH); goto EXIT; } @@ -638,164 +593,37 @@ mempressure_psi_init(void) return res; } -/** Start cgroup memory tracking - */ -static bool -mempressure_cgroup_init(void) -{ - bool res = false; - - /* Check threshold configuration */ - for( int i = MEMNOTIFY_LEVEL_WARNING; i <= MEMNOTIFY_LEVEL_CRITICAL; ++i ) { - if( !mempressure_limit_is_valid(&mempressure_limit[i]) ) { - mce_log(LL_WARN, "mempressure '%s' threshold is not defined", - memnotify_level_repr(i)); - goto EXIT; - } - } - - /* Get file descriptors */ - mce_log(LL_DEBUG, "create eventfd"); - if( (mempressure_cgroup_event_fd = eventfd(0, 0)) == -1 ) { - mce_log(LL_ERR, "create eventfd: %m"); - goto EXIT; - } - - mce_log(LL_DEBUG, "open %s", CGROUP_DATA_PATH); - if( (mempressure_cgroup_data_fd = open(CGROUP_DATA_PATH, O_RDONLY)) == -1 ) { - mce_log(LL_ERR, "%s: open: %m", CGROUP_DATA_PATH); - goto EXIT; - } - - mce_log(LL_DEBUG, "open %s", CGROUP_CTRL_PATH); - if( (mempressure_cgroup_ctrl_fd = open(CGROUP_CTRL_PATH, O_WRONLY)) == -1 ) { - mce_log(LL_ERR, "%s: open: %m", CGROUP_CTRL_PATH); - goto EXIT; - } - - /* Program notification limits */ - for( int i = MEMNOTIFY_LEVEL_WARNING; i <= MEMNOTIFY_LEVEL_CRITICAL; ++i ) { - int pages = mempressure_limit[i].mnl_used; - uint64_t bytes = mempressure_pages_to_bytes(pages); - - mce_log(LL_DEBUG, "mempressure %s threshold %" PRIu64 "", - memnotify_level_repr(i), bytes); - - char data[256]; - snprintf(data, sizeof data, "%d %d %" PRIu64 "\n", - mempressure_cgroup_event_fd, mempressure_cgroup_data_fd, bytes); - if( write(mempressure_cgroup_ctrl_fd, data, strlen(data)) == -1 ) { - mce_log(LL_ERR, "%s: write: %m", CGROUP_CTRL_PATH); - goto EXIT; - } - } - - /* Control fd is not needed after threshold setup is done */ - mce_log(LL_DEBUG, "close %s", CGROUP_CTRL_PATH); - close(mempressure_cgroup_ctrl_fd), - mempressure_cgroup_ctrl_fd = -1; - - /* Setup notification iowatch */ - mce_log(LL_DEBUG, "add eventfd iowatch"); - mempressure_cgroup_event_id = - mempressure_iowatch_add(mempressure_cgroup_event_fd, false, G_IO_IN, - mempressure_cgroup_event_cb, NULL); - if( !mempressure_cgroup_event_id ) { - mce_log(LL_ERR, "failed to add eventfd iowatch"); - goto EXIT; - } - - /* Evaluate and publish current state */ - if( !mempressure_cgroup_update_status() ) - goto EXIT; - - if( !mempressure_status_update_level() ) - goto EXIT; - - /* Initialization was successfully completed and we have broadcast - * a valid pressure level on memnotify_level_pipe - which should - * act as a signal for furthre to be loaded alternate memory pressure - * plugins to remain inactive. - */ - - res = true; - -EXIT: - - // all or nothing - if( !res ) - mempressure_cgroup_quit(); - - return res; -} - /** Set kernel side triggering levels and update current status */ static void -mempressure_cgroup_update_thresholds(void) +mempressure_psi_update_thresholds(void) { /* TODO: Is there some way to remove trigger thresholds? * * Meanwhile do a full reinitialization to get rid of old thresholds. */ - mempressure_cgroup_quit(); - mempressure_cgroup_init(); -} - -/** Read current memory use status from kernel side - */ -static bool -mempressure_cgroup_update_status(void) -{ - bool res = false; - - if( mempressure_cgroup_data_fd == -1 ) { - mce_log(LL_ERR, "data file not opened"); - goto EXIT; - } - - if( lseek(mempressure_cgroup_data_fd, 0, SEEK_SET) == -1 ) { - mce_log(LL_ERR, "failed to rewind data file: %m"); - goto EXIT; - } - - errno = 0; - - char tmp[256]; - int done = read(mempressure_cgroup_data_fd, tmp, sizeof tmp - 1); - if( done <= 0 ) { - mce_log(LL_ERR, "failed to read data file: %m"); - goto EXIT; - } - - tmp[done] = 0; - tmp[strcspn(tmp, "\n")] = 0; - - mce_log(LL_DEBUG, "status from data file: %s", tmp); - - if( !mempressure_limit_parse(&mempressure_status, tmp) ) { - mce_log(LL_ERR, "failed to parse status"); - goto EXIT; - } - - res = true; - -EXIT: - if( !res ) - mempressure_limit_clear(&mempressure_status); - - return res; + mempressure_psi_quit(); + mempressure_psi_init(); } /* ========================================================================= * * MEMPRESSURE_SETTING * ========================================================================= */ -/** GConf notification id for mempressure.warning.used level */ -static guint mempressure_setting_warning_used_id = 0; +/** GConf notification id for mempressure.window */ +static guint mempressure_setting_window_id = 0; + +/** GConf notification id for mempressure.warning.stall time */ +static guint mempressure_setting_warning_stall_id = 0; -/** GConf notification id for mempressure.critical.used level */ -static guint mempressure_setting_critical_used_id = 0; +/** GConf notification id for mempressure.warning.type */ +static guint mempressure_setting_warning_type_id = 0; + +/** GConf notification id for mempressure.critical.stall time */ +static guint mempressure_setting_critical_stall_id = 0; + +/** GConf notification id for mempressure.critical.type */ +static guint mempressure_setting_critical_type_id = 0; /** GConf callback for mempressure related settings * @@ -816,23 +644,47 @@ mempressure_setting_cb(GConfClient *const gcc, const guint id, if (gcv == NULL) { mce_log(LL_WARN, "GConf Key `%s' has been unset", gconf_entry_get_key(entry)); - } - else if( id == mempressure_setting_warning_used_id ) { - gint old = mempressure_limit[MEMNOTIFY_LEVEL_WARNING].mnl_used; + } else if ( id == mempressure_setting_window_id ) { + gint old = mempressure_window; gint val = gconf_value_get_int(gcv); if( old != val ) { - mce_log(LL_DEBUG, "mempressure.warning.used: %d -> %d", old, val); - mempressure_limit[MEMNOTIFY_LEVEL_WARNING].mnl_used = val; - mempressure_cgroup_update_thresholds(); + mce_log(LL_DEBUG, "mempressure.window: %d -> %d", old, val); + mempressure_window = val; + mempressure_psi_update_thresholds(); } - } - else if( id == mempressure_setting_critical_used_id ) { - gint old = mempressure_limit[MEMNOTIFY_LEVEL_CRITICAL].mnl_used; + } else if ( id == mempressure_setting_warning_stall_id ) { + gint old = mempressure_warning_stall; + gint val = gconf_value_get_int(gcv); + if( old != val ) { + mce_log(LL_DEBUG, "mempressure.warning.stall: %d -> %d", old, val); + mempressure_warning_stall = val; + mempressure_psi_update_thresholds(); + } + } else if ( id == mempressure_setting_warning_type_id ) { + char* old = mempressure_warning_type; + const char* val = gconf_value_get_string(gcv); + if( !mempressure_streq(old, val) ) { + mce_log(LL_DEBUG, "mempressure.warning.type: %s -> %s", old, val); + g_free(mempressure_warning_type); + mempressure_warning_type = g_strdup(val); + mempressure_psi_update_thresholds(); + } + } else if ( id == mempressure_setting_critical_stall_id ) { + gint old = mempressure_critical_stall; gint val = gconf_value_get_int(gcv); if( old != val ) { - mce_log(LL_DEBUG, "mempressure.critical.used: %d -> %d", old, val); - mempressure_limit[MEMNOTIFY_LEVEL_CRITICAL].mnl_used = val; - mempressure_cgroup_update_thresholds(); + mce_log(LL_DEBUG, "mempressure.critical.stall: %d -> %d", old, val); + mempressure_critical_stall = val; + mempressure_psi_update_thresholds(); + } + } else if ( id == mempressure_setting_critical_type_id ) { + char* old = mempressure_critical_type; + const char* val = gconf_value_get_string(gcv); + if( !mempressure_streq(old, val) ) { + mce_log(LL_DEBUG, "mempressure.critical.type: %s -> %s", old, val); + g_free(mempressure_critical_type); + mempressure_critical_type = g_strdup(val); + mempressure_psi_update_thresholds(); } } else { @@ -846,36 +698,79 @@ mempressure_setting_cb(GConfClient *const gcc, const guint id, */ static void mempressure_setting_init(void) { - /* mempressure.warning.used level */ - mce_setting_notifier_add(MCE_SETTING_MEMNOTIFY_WARNING_PATH, - MCE_SETTING_MEMNOTIFY_WARNING_USED, + mce_setting_notifier_add(MCE_SETTING_MEMPRESSURE_PATH, + MCE_SETTING_MEMPRESSURE_WINDOW, + mempressure_setting_cb, + &mempressure_setting_window_id); + + mce_setting_get_int(MCE_SETTING_MEMPRESSURE_WINDOW, + &mempressure_window); + + mce_setting_notifier_add(MCE_SETTING_MEMPRESSURE_WARNING_PATH, + MCE_SETTING_MEMPRESSURE_WARNING_STALL, + mempressure_setting_cb, + &mempressure_setting_warning_stall_id); + + mce_setting_get_int(MCE_SETTING_MEMPRESSURE_WARNING_STALL, + &mempressure_warning_stall); + + mce_setting_notifier_add(MCE_SETTING_MEMPRESSURE_WARNING_PATH, + MCE_SETTING_MEMPRESSURE_WARNING_TYPE, mempressure_setting_cb, - &mempressure_setting_warning_used_id); + &mempressure_setting_warning_type_id); + + mce_setting_get_string(MCE_SETTING_MEMPRESSURE_WARNING_TYPE, + &mempressure_warning_type); - mce_setting_get_int(MCE_SETTING_MEMNOTIFY_WARNING_USED, - &mempressure_limit[MEMNOTIFY_LEVEL_WARNING].mnl_used); + if ( mempressure_warning_type == NULL ) { + mempressure_warning_type = g_strdup(MCE_DEFAULT_MEMPRESSURE_WARNING_TYPE); + } - /* mempressure.critical.used level */ - mce_setting_notifier_add(MCE_SETTING_MEMNOTIFY_CRITICAL_PATH, - MCE_SETTING_MEMNOTIFY_CRITICAL_USED, + mce_setting_notifier_add(MCE_SETTING_MEMPRESSURE_CRITICAL_PATH, + MCE_SETTING_MEMPRESSURE_CRITICAL_STALL, mempressure_setting_cb, - &mempressure_setting_critical_used_id); + &mempressure_setting_critical_stall_id); - mce_setting_get_int(MCE_SETTING_MEMNOTIFY_CRITICAL_USED, - &mempressure_limit[MEMNOTIFY_LEVEL_CRITICAL].mnl_used); + mce_setting_get_int(MCE_SETTING_MEMPRESSURE_CRITICAL_STALL, + &mempressure_critical_stall); - mempressure_status_show_triggers(); + mce_setting_notifier_add(MCE_SETTING_MEMPRESSURE_CRITICAL_PATH, + MCE_SETTING_MEMPRESSURE_CRITICAL_TYPE, + mempressure_setting_cb, + &mempressure_setting_critical_type_id); + + mce_setting_get_string(MCE_SETTING_MEMPRESSURE_CRITICAL_TYPE, + &mempressure_critical_type); + + if ( mempressure_critical_type == NULL ) { + mempressure_critical_type = g_strdup(MCE_DEFAULT_MEMPRESSURE_CRITICAL_TYPE); + } } /** Stop tracking setting changes */ static void mempressure_setting_quit(void) { - mce_setting_notifier_remove(mempressure_setting_warning_used_id), - mempressure_setting_warning_used_id = 0; + mce_setting_notifier_remove(mempressure_setting_window_id), + mempressure_setting_window_id = 0; - mce_setting_notifier_remove(mempressure_setting_critical_used_id), - mempressure_setting_critical_used_id = 0; + mce_setting_notifier_remove(mempressure_setting_warning_stall_id), + mempressure_setting_warning_stall_id = 0; + + mce_setting_notifier_remove(mempressure_setting_warning_type_id), + mempressure_setting_warning_type_id = 0; + + g_free(mempressure_warning_type); + mempressure_warning_type = NULL; + + mce_setting_notifier_remove(mempressure_setting_critical_stall_id), + mempressure_setting_critical_stall_id = 0; + + mce_setting_notifier_remove(mempressure_setting_critical_type_id), + mempressure_setting_critical_type_id = 0; + + g_free(mempressure_critical_type); + mempressure_critical_type = NULL; } /* ========================================================================= * @@ -885,7 +780,7 @@ static void mempressure_setting_quit(void) static void mempressure_plugin_quit(void) { - mempressure_cgroup_quit(); + mempressure_psi_quit(); mempressure_setting_quit(); } @@ -896,9 +791,6 @@ mempressure_plugin_init(void) mempressure_setting_init(); - if( !mempressure_cgroup_init() ) - goto EXIT; - if ( !mempressure_psi_init() ) goto EXIT; @@ -935,8 +827,8 @@ G_MODULE_EXPORT const gchar *g_module_check_init(GModule *module) } /* Check if required sysfs files are present */ - if( !mempressure_cgroup_is_available() ) { - mce_log(LL_WARN, "mempressure cgroup interface not available"); + if( !mempressure_psi_is_available() ) { + mce_log(LL_WARN, "mempressure psi interface not available"); goto EXIT; } diff --git a/modules/mempressure.h b/modules/mempressure.h new file mode 100644 index 0000000..3272dbf --- /dev/null +++ b/modules/mempressure.h @@ -0,0 +1,58 @@ +/** + * @file mempressure.h + * Memory use tracking and notification plugin for the Mode Control Entity + *

+ * Copyright (C) 2014-2019 Jolla Ltd. + *

+ * @author Simo Piiroinen + * + * mce is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * mce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mce. If not, see . + */ + +#ifndef MEMPRESSURE_H_ +# define MEMPRESSURE_H_ + +/* ========================================================================= * + * Settings + * ========================================================================= */ + +/** Prefix for mempressure setting keys */ +# define MCE_SETTING_MEMPRESSURE_PATH "/system/osso/dsm/mempressure" + +/** PSI tracking window [us] */ +# define MCE_SETTING_MEMPRESSURE_WINDOW MCE_SETTING_MEMPRESSURE_PATH"/window" +# define MCE_DEFAULT_MEMPRESSURE_WINDOW 1000000 + +/** Memnotify warning level configuration */ +# define MCE_SETTING_MEMPRESSURE_WARNING_PATH MCE_SETTING_MEMPRESSURE_PATH"/warning" + +/** Warning threshold stall stall time [us] */ +# define MCE_SETTING_MEMPRESSURE_WARNING_STALL MCE_SETTING_MEMPRESSURE_PATH"/warning/stall" +# define MCE_DEFAULT_MEMPRESSURE_WARNING_STALL 100000 + +/** Warning threshold type (some or full) */ +# define MCE_SETTING_MEMPRESSURE_WARNING_TYPE MCE_SETTING_MEMPRESSURE_PATH"/warning/type" +# define MCE_DEFAULT_MEMPRESSURE_WARNING_TYPE "some" + +/** Memnotify critical level configuration */ +# define MCE_SETTING_MEMPRESSURE_CRITICAL_PATH MCE_SETTING_MEMPRESSURE_PATH"/critical" + +/** Critical threshold for stall time [us] */ +# define MCE_SETTING_MEMPRESSURE_CRITICAL_STALL MCE_SETTING_MEMPRESSURE_PATH"/critical/stall" +# define MCE_DEFAULT_MEMPRESSURE_CRITICAL_STALL 150000 + +/** Critica threshold type (some or full) */ +# define MCE_SETTING_MEMPRESSURE_CRITICAL_TYPE MCE_SETTING_MEMPRESSURE_PATH"/critical/type" +# define MCE_DEFAULT_MEMPRESSURE_CRITICAL_TYPE "full" + +#endif /* MEMPRESSURE_H_ */ From 42c5606a68b0ea1cc33be9fefa9b143e3c467b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Karas?= Date: Sun, 28 Aug 2022 01:28:31 +0200 Subject: [PATCH 7/7] cleanup --- modules/mempressure.c | 237 ++---------------------------------------- 1 file changed, 6 insertions(+), 231 deletions(-) diff --git a/modules/mempressure.c b/modules/mempressure.c index 2fac8aa..9c5b395 100644 --- a/modules/mempressure.c +++ b/modules/mempressure.c @@ -36,24 +36,8 @@ #include #include -// /* Paths to relevant cgroup data/control files */ -// #define CGROUP_MEMORY_DIRECTORY "/sys/fs/cgroup/memory" -// #define CGROUP_DATA_PATH CGROUP_MEMORY_DIRECTORY "/memory.usage_in_bytes" -// #define CGROUP_CTRL_PATH CGROUP_MEMORY_DIRECTORY "/cgroup.event_control" - #define PSI_MEMORY_PATH "/proc/pressure/memory" -/* ========================================================================= * - * Types - * ========================================================================= */ - -/** Structure for holding for /dev/mempressure compatible limit data */ -// typedef struct -// { -// /** Estimate of number of non-discardable RAM pages */ -// gint mnl_used; -// } mempressure_limit_t; - /* ========================================================================= * * Prototypes * ========================================================================= */ @@ -62,29 +46,18 @@ * UTILITY * ------------------------------------------------------------------------- */ -// static int mempressure_bytes_to_pages(uint64_t bytes); -// static uint64_t mempressure_pages_to_bytes(int pages); static guint mempressure_iowatch_add (int fd, bool close_on_unref, GIOCondition cnd, GIOFunc io_cb, gpointer aptr); static bool mempressure_streq (const char *s1, const char *s2); /* ------------------------------------------------------------------------- * - * MEMPRESSURE_STATUS + * MEMPRESSURE_PSI * ------------------------------------------------------------------------- */ -// static memnotify_level_t mempressure_status_evaluate_level(void); -// static bool mempressure_status_update_level (void); -// static void mempressure_status_show_triggers (void); +static bool mempressure_psi_is_available (void); +static gboolean mempressure_psi_event_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr); +static void mempressure_psi_quit (void); +static bool mempressure_psi_init (void); -/* ------------------------------------------------------------------------- * - * MEMPRESSURE_CGROUP - * ------------------------------------------------------------------------- */ - -// static bool mempressure_cgroup_is_available (void); -// static gboolean mempressure_cgroup_event_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr); -// static void mempressure_cgroup_quit (void); -// static bool mempressure_cgroup_init (void); -// static bool mempressure_cgroup_update_status (void); -// /* ------------------------------------------------------------------------- * * MEMPRESSURE_SETTING @@ -112,23 +85,6 @@ void g_module_unload (GModule *module); * UTILITY * ========================================================================= */ -// /* Convert kernel reported byte count to page count used in configuration -// */ -// static int mempressure_bytes_to_pages(uint64_t bytes) -// { -// return (int)(bytes / PAGE_SIZE); -// } -// -// /* Convert configuration page count to bytes for use in kernel interface -// */ -// static uint64_t mempressure_pages_to_bytes(int pages) -// { -// if( pages < 0 ) -// pages = 0; -// return PAGE_SIZE * (uint64_t)pages; -// } -// - /** Add a glib I/O notification for a file descriptor */ static guint @@ -168,62 +124,6 @@ static bool mempressure_streq(const char *s1, const char *s2) return (s1 && s2) ? !strcmp(s1, s2) : (s1 == s2); } -/* ========================================================================= * - * MEMPRESSURE_LIMIT - * ========================================================================= */ - -// /** Reset limit object values -// */ -// static void -// mempressure_limit_clear(mempressure_limit_t *self) -// { -// self->mnl_used = 0; -// } -// -// /** Limit validity predicate -// */ -// static bool -// mempressure_limit_is_valid(const mempressure_limit_t *self) -// { -// return self->mnl_used > 0; -// } -// -// /** Convert limit object values to /dev/mempressure compatible ascii form -// */ -// static int -// mempressure_limit_repr(const mempressure_limit_t *self, char *data, size_t size) -// { -// int res = snprintf(data, size, "used %d", self->mnl_used); -// return res; -// } -// -// /** Parse limit object from /sys/fs/cgroup/memory/memory.usage_in_bytes format -// */ -// static bool -// mempressure_limit_parse(mempressure_limit_t *self, const char *data) -// { -// char *end = 0; -// uint64_t val = strtoull(data, &end, 10); -// bool res = end > data && *end == 0; -// -// if( !res ) -// mce_log(LL_ERR, "parse error: '%s' is not a number", data); -// else -// self->mnl_used = mempressure_bytes_to_pages(val); -// -// return res; -// } -// -// /** Check if limit object values are exceeded by given state data -// */ -// static bool -// mempressure_limit_exceeded(const mempressure_limit_t *self, -// const mempressure_limit_t *status) -// { -// return (mempressure_limit_is_valid(self) && -// self->mnl_used <= status->mnl_used); -// } - /* ========================================================================= * * MEMPRESSURE_STATUS * ========================================================================= */ @@ -238,45 +138,10 @@ static char* mempressure_critical_type = NULL; /** Cached memory use level */ static memnotify_level_t mempressure_level = MEMNOTIFY_LEVEL_UNKNOWN; -/** Re-evaluate memory use level and broadcast changes via datapipe - */ -// static bool -// mempressure_status_update_level(void) -// { -// memnotify_level_t prev = mempressure_level; -// mempressure_level = mempressure_status_evaluate_level(); -// -// if( mempressure_level == prev ) -// goto EXIT; -// -// mce_log(LL_WARN, "mempressure_level: %s -> %s", -// memnotify_level_repr(prev), -// memnotify_level_repr(mempressure_level)); -// -// datapipe_exec_full(&memnotify_level_pipe, -// GINT_TO_POINTER(mempressure_level)); -// -// EXIT: -// -// return mempressure_level != MEMNOTIFY_LEVEL_UNKNOWN; -// } - /* ========================================================================= * - * MEMPRESSURE_CGROUP + * MEMPRESSURE_PSI * ========================================================================= */ -/** File descriptor for CGROUP_DATA_PATH */ -// static int mempressure_cgroup_data_fd = -1; - -/** File descriptor for CGROUP_CTRL_PATH */ -// static int mempressure_cgroup_ctrl_fd = -1; - -/** Eventfd for receiving notifications about threshold crossings */ -// static int mempressure_cgroup_event_fd = -1; - -/** I/O watch for mempressure_cgroup_event_fd */ -// static guint mempressure_cgroup_event_id = 0; - /** Probe if the required PSI sysfs files are present */ static bool @@ -285,96 +150,6 @@ mempressure_psi_is_available(void) return access(PSI_MEMORY_PATH, R_OK) == 0; } -/** Input watch callback for cgroup memory threshold crossings - */ -// static gboolean -// mempressure_cgroup_event_cb(GIOChannel *chn, GIOCondition cnd, gpointer aptr) -// { -// (void) chn; -// (void) aptr; -// -// gboolean ret = G_SOURCE_REMOVE; -// -// if( !mempressure_cgroup_event_id ) -// goto EXIT; -// -// if( mempressure_cgroup_event_fd == -1 ) -// goto EXIT; -// -// if( mempressure_cgroup_data_fd == -1 ) -// goto EXIT; -// -// mce_log(LL_DEBUG, "eventfd iowatch notify"); -// -// if( cnd & ~G_IO_IN ) { -// mce_log(LL_ERR, "unexpected input watch condition"); -// goto EXIT; -// } -// -// uint64_t count = 0; -// ssize_t rc = read(mempressure_cgroup_event_fd, &count, sizeof count); -// -// if( rc == 0 ) { -// mce_log(LL_ERR, "eventfd eof"); -// goto EXIT; -// } -// -// if( rc == -1 ) { -// if( errno == EINTR || errno == EAGAIN ) -// ret = G_SOURCE_CONTINUE; -// else -// mce_log(LL_ERR, "eventfd error: %m"); -// goto EXIT; -// } -// -// if( mempressure_cgroup_update_status() ) -// ret = G_SOURCE_CONTINUE; -// -// /* Update level anyway -> if we disable iowatch due to -// * read/parse errors, the level gets reset to 'unknown'. -// */ -// mempressure_status_update_level(); -// -// EXIT: -// -// if( ret == G_SOURCE_REMOVE && mempressure_cgroup_event_id ) { -// mempressure_cgroup_event_id = 0; -// mce_log(LL_CRIT, "disabling eventfd iowatch"); -// } -// -// return ret; -// } -// -// /** Stop cgroup memory tracking -// */ -// static void -// mempressure_cgroup_quit(void) -// { -// if( mempressure_cgroup_event_id ) { -// mce_log(LL_DEBUG, "remove eventfd iowatch"); -// g_source_remove(mempressure_cgroup_event_id), -// mempressure_cgroup_event_id = 0; -// } -// -// if( mempressure_cgroup_event_fd != -1 ) { -// mce_log(LL_DEBUG, "close eventfd"); -// close(mempressure_cgroup_event_fd), -// mempressure_cgroup_event_fd = -1; -// } -// -// if( mempressure_cgroup_ctrl_fd != -1 ) { -// mce_log(LL_DEBUG, "close %s", CGROUP_CTRL_PATH); -// close(mempressure_cgroup_ctrl_fd), -// mempressure_cgroup_ctrl_fd = -1; -// } -// -// if( mempressure_cgroup_data_fd != -1 ) { -// mce_log(LL_DEBUG, "close %s", CGROUP_DATA_PATH); -// close(mempressure_cgroup_data_fd), -// mempressure_cgroup_data_fd = -1; -// } -// } - static int mempressure_psi_warning_fd = -1; static int mempressure_psi_critical_fd = -1; static guint mempressure_psi_warn_event_id = 0;