From 6bba9ec53d65736a208c2322753a001d80a4e831 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Sun, 19 Mar 2023 23:58:27 +0000 Subject: [PATCH] Refactor Memory Monitor The launchpad memory monitor is implemented using C++ language. Change-Id: I13a530d912a43ecff1271e78ede22334da9344c3 Signed-off-by: Hwankyu Jhun --- src/launchpad-process-pool/launchpad.cc | 82 +++++++----- .../launchpad_memory_monitor.cc | 142 --------------------- src/launchpad-process-pool/memory_monitor.cc | 95 ++++++++++++++ src/launchpad-process-pool/memory_monitor.hh | 57 +++++++++ src/lib/launchpad-common/procfs.cc | 113 ++++++++++++++++ .../launchpad-common/procfs.hh} | 28 ++-- 6 files changed, 334 insertions(+), 183 deletions(-) delete mode 100644 src/launchpad-process-pool/launchpad_memory_monitor.cc create mode 100644 src/launchpad-process-pool/memory_monitor.cc create mode 100644 src/launchpad-process-pool/memory_monitor.hh create mode 100644 src/lib/launchpad-common/procfs.cc rename src/{launchpad-process-pool/launchpad_memory_monitor.h => lib/launchpad-common/procfs.hh} (51%) diff --git a/src/launchpad-process-pool/launchpad.cc b/src/launchpad-process-pool/launchpad.cc index 0980599..cb240cc 100644 --- a/src/launchpad-process-pool/launchpad.cc +++ b/src/launchpad-process-pool/launchpad.cc @@ -41,25 +41,26 @@ #include #include +#include + #include "launchpad-process-pool/debug.hh" #include "launchpad-process-pool/launcher_info.hh" #include "launchpad-process-pool/launchpad_config.h" #include "launchpad-process-pool/launchpad_debug.h" #include "launchpad-process-pool/launchpad_inotify.h" #include "launchpad-process-pool/launchpad_io_channel.h" -#include "launchpad-process-pool/launchpad_memory_monitor.h" #include "launchpad-process-pool/launchpad_signal.h" #include "launchpad-process-pool/loader_info.hh" #include "launchpad-process-pool/slot_info.h" #include "lib/common/inc/key.h" #include "lib/common/inc/launchpad_common.h" #include "lib/common/inc/launchpad_plugin.h" -#include "lib/common/inc/launchpad_proc.h" #include "lib/common/inc/launchpad_types.h" #include "lib/common/inc/perf.h" #include "launchpad-process-pool/dbus.hh" #include "launchpad-process-pool/log.hh" +#include "launchpad-process-pool/memory_monitor.hh" #include "launchpad-process-pool/worker.hh" #define AUL_PR_NAME 16 @@ -130,7 +131,7 @@ typedef struct { io_channel_h channel = nullptr; io_channel_h hydra_channel = nullptr; unsigned int score = 0; - unsigned int pss = 0; + uint64_t pss = 0; int cpu_check_count = 0; int on_boot_timeout = 0; guint on_boot_timer = 0; @@ -200,6 +201,8 @@ typedef request_t* request_h; typedef int (*request_handler)(request_h request); +static void HandleMemoryStatusChangedEvent(bool low_memory); + namespace { class CleanupInfo : public launchpad::Worker::Job { @@ -218,6 +221,36 @@ class CleanupInfo : public launchpad::Worker::Job { pid_t pid_; }; +class MemoryManager : public launchpad::MemoryMonitor, + public launchpad::MemoryMonitor::IEvent { + public: + MemoryManager(const MemoryManager&) = delete; + MemoryManager& operator = (const MemoryManager&) = delete; + MemoryManager(MemoryManager&&) = delete; + MemoryManager& operator = (MemoryManager&&) = delete; + + static MemoryManager& GetInst() { + static MemoryManager inst; + return inst; + } + + void Init() { + Start(); + } + + void Finish() { + Stop(); + } + + private: + MemoryManager() : MemoryMonitor(this) {} + ~MemoryManager() {} + + void OnMemoryStatusChanged(bool low_memory) override { + HandleMemoryStatusChangedEvent(low_memory); + } +}; + int __sys_hwacc; std::unique_ptr loader_info_manager; std::unique_ptr app_defined_loader_info_manager; @@ -520,7 +553,7 @@ static void __update_slots_pss(void) { if (cpc->pid == CANDIDATE_NONE) continue; - _proc_get_mem_pss(cpc->pid, &cpc->pss); + launchpad::Procfs::GetPssMemory(cpc->pid, &cpc->pss); } } @@ -571,7 +604,7 @@ static void __pause_all_running_slots(bool is_hydra) { cpc = reinterpret_cast(iter->data); if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE) { __update_slot_state(cpc, launchpad::LoaderMethod::OutOfMemory, true); - if (!_memory_monitor_is_low_memory()) + if (!MemoryManager::GetInst().IsLowMemory()) return; } @@ -972,7 +1005,7 @@ static int __prepare_candidate_process(int type, int loader_id) { launchpad::Log::Print("[CANDIDATE]", "pid(%7d) | type(%d) | loader(%s)", info->pid, cpt->loader_id, cpt->loader_name); - _memory_monitor_reset_timer(); + MemoryManager::GetInst().Reset(); __candidate_info_free(info); return 0; } @@ -2009,17 +2042,13 @@ static int __dispatch_cmd_remove_loader(bundle* kb) { } static int __check_caller_by_pid(int pid) { - int ret; - char buf[PATH_MAX] = { - 0, - }; - - ret = _proc_get_attr(pid, buf, sizeof(buf)); - if (ret < 0) + std::string attr = launchpad::Procfs::GetAttrCurrent(pid); + if (attr.empty()) return -1; - if (strcmp(buf, "User") == 0 || strcmp(buf, "System") == 0 || - strcmp(buf, "System::Privileged") == 0) + if (attr.compare("User") == 0 || + attr.compare("System") == 0 || + attr.compare("System::Privileged") == 0) return 0; return -1; @@ -2425,7 +2454,7 @@ static int __launch_request_prepare(request_h request) { } static void __launch_request_complete(request_h request) { - _memory_monitor_reset_timer(); + MemoryManager::GetInst().Reset(); __request_send_result(request, request->pid); if (request->pid > 0) { @@ -3011,7 +3040,7 @@ static void __add_app_defined_loaders(void) { } static bool __is_low_memory(void) { - if (_memory_monitor_is_low_memory()) + if (MemoryManager::GetInst().IsLowMemory()) return true; if (__memory_status_low >= MEMORY_STATUS_LOW) @@ -3226,14 +3255,12 @@ static int __init_logger_fd(void) { return 0; } -static int __memory_monitor_cb(bool low_memory, void* user_data) { - candidate_process_context_t* cpc; - - cpc = __get_running_slot(false); - if (!cpc && low_memory) - return -1; - +static void HandleMemoryStatusChangedEvent(bool low_memory) { if (low_memory) { + candidate_process_context_t* cpc = __get_running_slot(false); + if (cpc == nullptr) + return; + _W("Low memory"); __update_slots_pss(); @@ -3242,8 +3269,6 @@ static int __memory_monitor_cb(bool low_memory, void* user_data) { } else { __resume_all_slots(); } - - return 0; } static gboolean __logger_recovery_cb(gpointer data) { @@ -3332,8 +3357,7 @@ static int __before_loop(int argc, char** argv) { _W("Failed to initialize config"); _inotify_init(); - _memory_monitor_init(); - _memory_monitor_set_event_cb(__memory_monitor_cb, nullptr); + MemoryManager::GetInst().Init(); MAX_CPU_CHECK_COUNT = _config_get_int_value(CONFIG_TYPE_CPU_CHECKER_MAX_COUNT); @@ -3366,7 +3390,7 @@ static int __before_loop(int argc, char** argv) { static void __after_loop(void) { launchpad::Log::Finish(); cleaner.reset(); - _memory_monitor_fini(); + MemoryManager::GetInst().Finish(); __unregister_vconf_events(); if (__pid_table) g_hash_table_destroy(__pid_table); diff --git a/src/launchpad-process-pool/launchpad_memory_monitor.cc b/src/launchpad-process-pool/launchpad_memory_monitor.cc deleted file mode 100644 index c69fe73..0000000 --- a/src/launchpad-process-pool/launchpad_memory_monitor.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "launchpad-process-pool/launchpad_memory_monitor.h" - -#include -#include -#include -#include -#include - -#include "launchpad-process-pool/launchpad_config.h" -#include "lib/common/inc/launchpad_proc.h" -#include "lib/common/inc/log_private.h" - -#define INTERVAL_BASE_RATE 0.15f - -struct memory_monitor_s { - unsigned int threshold; - unsigned int prev_used_ratio; - unsigned int base_interval; - unsigned int interval; - bool low_memory; - guint tag; - memory_monitor_cb callback; - void* user_data; -}; - -static struct memory_monitor_s __monitor; - -static void __memory_monitor_start(void); - -static gboolean __memory_check_cb(gpointer data) { - bool low_memory; - - __monitor.tag = 0; - low_memory = _memory_monitor_is_low_memory(); - if (__monitor.low_memory != low_memory && __monitor.callback) - __monitor.callback(low_memory, __monitor.user_data); - - __monitor.low_memory = low_memory; - __memory_monitor_start(); - - return G_SOURCE_REMOVE; -} - -static void __memory_monitor_stop(void) { - if (!__monitor.tag) - return; - - g_source_remove(__monitor.tag); - __monitor.tag = 0; -} - -static void __memory_monitor_start(void) { - if (__monitor.threshold == 100) - return; - - if (__monitor.tag) - return; - - __monitor.tag = g_timeout_add(__monitor.interval, __memory_check_cb, NULL); - - __monitor.interval += __monitor.interval * INTERVAL_BASE_RATE; -} - -int _memory_monitor_reset_timer(void) { - _W("Reset"); - __monitor.interval = __monitor.base_interval; - - __memory_monitor_stop(); - __memory_monitor_start(); - - return 0; -} - -bool _memory_monitor_is_low_memory(void) { - unsigned int mem_used_ratio = 0; - - if (__monitor.threshold == 100) - return false; - - _proc_get_mem_used_ratio(&mem_used_ratio); - - _W("previous used ratio(%u), current used ratio(%u)", - __monitor.prev_used_ratio, mem_used_ratio); - - __monitor.prev_used_ratio = mem_used_ratio; - - if (mem_used_ratio > __monitor.threshold) - return true; - - return false; -} - -int _memory_monitor_set_event_cb(memory_monitor_cb callback, void* user_data) { - __monitor.callback = callback; - __monitor.user_data = user_data; - - return 0; -} - -int _memory_monitor_init(void) { - int ret; - - _W("MEMORY_MONITOR_INIT"); - - __monitor.threshold = - _config_get_int_value(CONFIG_TYPE_MEMORY_MONITOR_THRESHOLD); - __monitor.base_interval = - _config_get_int_value(CONFIG_TYPE_MEMORY_MONITOR_INTERVAL); - __monitor.interval = __monitor.base_interval; - - ret = _proc_get_mem_used_ratio(&__monitor.prev_used_ratio); - if (ret != 0) { - _E("Failed to get mem used ratio. error(%d)", ret); - return ret; - } - - __memory_monitor_start(); - - return 0; -} - -void _memory_monitor_fini(void) { - _W("MEMORY_MONITOR_FINI"); - - __memory_monitor_stop(); -} diff --git a/src/launchpad-process-pool/memory_monitor.cc b/src/launchpad-process-pool/memory_monitor.cc new file mode 100644 index 0000000..54acde4 --- /dev/null +++ b/src/launchpad-process-pool/memory_monitor.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "launchpad-process-pool/memory_monitor.hh" + +#include + +#include "launchpad-process-pool/launchpad_config.h" +#include "launchpad-process-pool/log_private.hh" + +namespace launchpad { +namespace { + +constexpr const float INTERVAL_BASE_RATE = 0.15f; + +} // namespace + +MemoryMonitor::MemoryMonitor(IEvent* listener) : listener_(listener) { + threshold_ = _config_get_int_value(CONFIG_TYPE_MEMORY_MONITOR_THRESHOLD); + base_interval_ = _config_get_int_value(CONFIG_TYPE_MEMORY_MONITOR_INTERVAL); + interval_ = base_interval_; +} + +MemoryMonitor::~MemoryMonitor() { + Stop(); +} + +bool MemoryMonitor::IsLowMemory() { + if (threshold_ == 100) + return false; + + uint32_t usage = 0; + Procfs::GetMemoryUsage(&usage); + _W("Previous used ratio: %u, current used ratio: %u", + previous_usage_, usage); + previous_usage_ = usage; + + if (usage > threshold_) + return true; + + return false; +} + +void MemoryMonitor::Reset() { + _W("Reset"); + interval_ = base_interval_; + + Stop(); + Start(); +} + +void MemoryMonitor::Start() { + if (threshold_ == 100) + return; + + if (timer_ != 0) + return; + + timer_ = g_timeout_add(interval_, TimeoutCb, this); + interval_ += interval_ * INTERVAL_BASE_RATE; +} + +void MemoryMonitor::Stop() { + if (timer_ != 0) { + g_source_remove(timer_); + timer_ = 0; + } +} + +gboolean MemoryMonitor::TimeoutCb(gpointer user_data) { + auto* handle = static_cast(user_data); + handle->timer_ = 0; + bool low_memory = handle->IsLowMemory(); + if (low_memory != handle->low_memory_ && handle->listener_) + handle->listener_->OnMemoryStatusChanged(low_memory); + + handle->low_memory_ = low_memory; + handle->Start(); + return G_SOURCE_REMOVE; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/memory_monitor.hh b/src/launchpad-process-pool/memory_monitor.hh new file mode 100644 index 0000000..34f9a2c --- /dev/null +++ b/src/launchpad-process-pool/memory_monitor.hh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LAUNCHPAD_PROCESS_POOL_MEMORY_MONITOR_HH_ +#define LAUNCHPAD_PROCESS_POOL_MEMORY_MONITOR_HH_ + +#include + +#include + +namespace launchpad { + +class MemoryMonitor { + public: + class IEvent { + public: + virtual ~IEvent() = default; + virtual void OnMemoryStatusChanged(bool low_memory) = 0; + }; + + explicit MemoryMonitor(IEvent* listener); + virtual ~MemoryMonitor(); + + bool IsLowMemory(); + void Reset(); + void Stop(); + void Start(); + + private: + static gboolean TimeoutCb(gpointer user_data); + + private: + IEvent* listener_; + uint32_t threshold_ = 0; + uint32_t previous_usage_ = 0; + guint base_interval_ = 0; + guint interval_ = 0; + guint timer_ = 0; + bool low_memory_ = false; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_MEMORY_MONITOR_HH_ diff --git a/src/lib/launchpad-common/procfs.cc b/src/lib/launchpad-common/procfs.cc new file mode 100644 index 0000000..ac9596b --- /dev/null +++ b/src/lib/launchpad-common/procfs.cc @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "launchpad-common/procfs.hh" + +#include + +#include +#include +#include +#include +#include + +#include "launchpad-common/log_private.hh" + +namespace launchpad { + +void Procfs::GetMemoryUsage(uint32_t* usage) { + if (usage == nullptr) { + _E("Invalid argument"); + return; + } + + uint64_t mem_total = 0; + uint64_t mem_free = 0; + uint64_t mem_available = 0; + uint64_t mem_cached = 0; + + std::ifstream stream("/proc/meminfo"); + std::string line; + while (getline(stream, line)) { + std::istringstream iss(line); + std::string key; + uint64_t value; + + if (iss >> key >> value) { + if (key == "MemTotal:") + mem_total = value; + else if (key == "MemAvailable:") + mem_available = value; + else if (key == "MemFree:") + mem_free = value; + else if (key == "Cached:") + mem_cached = value; + } + } + + if (mem_total == 0) { + _E("Failed to get total memory size"); + return; + } + + if (mem_available == 0) + mem_available = mem_free + mem_cached; + + *usage = (mem_total - mem_available) * 100 / mem_total; + _W("usage: %u %%", *usage); +} + +void Procfs::GetPssMemory(pid_t pid, uint64_t* mem_pss) { + if (pid < 1 || mem_pss == nullptr) { + _E("Invalid parameter"); + return; + } + + std::ifstream file("/proc/" + std::to_string(pid) + "/smaps"); + std::string line; + uint64_t total_pss = 0; + + while (std::getline(file, line)) { + uint64_t pss = 0; + if (std::sscanf(line.c_str(), "Pss: %llu kB", &pss) == 1) + total_pss += pss; + } + + *mem_pss = total_pss; +} + +std::string Procfs::GetAttrCurrent(pid_t pid) { + const std::string path = "/proc/" + std::to_string(pid) + "/attr/current"; + std::ifstream file(path); + if (!file.is_open()) { + _E("%s is not opened", path.c_str()); + return {}; + } + + std::stringstream buffer; + buffer << file.rdbuf(); + file.close(); + + const std::string result = buffer.str(); + if (result.empty()) { + _E("file is empty"); + return {}; + } + + return result; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/launchpad_memory_monitor.h b/src/lib/launchpad-common/procfs.hh similarity index 51% rename from src/launchpad-process-pool/launchpad_memory_monitor.h rename to src/lib/launchpad-common/procfs.hh index a8486be..4c45e7a 100644 --- a/src/launchpad-process-pool/launchpad_memory_monitor.h +++ b/src/lib/launchpad-common/procfs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. @@ -14,21 +14,25 @@ * limitations under the License. */ -#ifndef __LAUNCHPAD_MEMORY_MONITOR_H__ -#define __LAUNCHPAD_MEMORY_MONITOR_H__ +#ifndef LIB_LAUNCHPAD_COMMON_PROCFS_HH_ +#define LIB_LAUNCHPAD_COMMON_PROCFS_HH_ -#include +#include -typedef int (*memory_monitor_cb)(bool low_memory, void *user_data); +#include -int _memory_monitor_init(void); +#undef EXPORT_API +#define EXPORT_API __attribute__((visibility("default"))) -void _memory_monitor_fini(void); +namespace launchpad { -int _memory_monitor_set_event_cb(memory_monitor_cb callback, void *user_data); +class EXPORT_API Procfs { + public: + static void GetMemoryUsage(uint32_t* usage); + static void GetPssMemory(pid_t pid, uint64_t* mem_pss); + static std::string GetAttrCurrent(pid_t pid); +}; -int _memory_monitor_reset_timer(void); +} // namespace launchpad -bool _memory_monitor_is_low_memory(void); - -#endif /* __LAUNCHPAD_MEMORY_MONITOR_H__ */ +#endif // LIB_LAUNCHPAD_COMMON_PROCFS_HH_ -- 2.7.4