The launchpad memory monitor is implemented using C++ language.
Change-Id: I13a530d912a43ecff1271e78ede22334da9344c3
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
#include <algorithm>
#include <string>
+#include <procfs.hh>
+
#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
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;
typedef int (*request_handler)(request_h request);
+static void HandleMemoryStatusChangedEvent(bool low_memory);
+
namespace {
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<launchpad::LoaderInfoManager> loader_info_manager;
std::unique_ptr<launchpad::LoaderInfoManager> app_defined_loader_info_manager;
if (cpc->pid == CANDIDATE_NONE)
continue;
- _proc_get_mem_pss(cpc->pid, &cpc->pss);
+ launchpad::Procfs::GetPssMemory(cpc->pid, &cpc->pss);
}
}
cpc = reinterpret_cast<candidate_process_context_t*>(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;
}
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;
}
}
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;
}
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) {
}
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)
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();
} else {
__resume_all_slots();
}
-
- return 0;
}
static gboolean __logger_recovery_cb(gpointer data) {
_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);
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);
+++ /dev/null
-/*
- * 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 <errno.h>
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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();
-}
--- /dev/null
+/*
+ * 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 <procfs.hh>
+
+#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<MemoryMonitor*>(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
--- /dev/null
+/*
+ * 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 <glib.h>
+
+#include <cstdint>
+
+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_
--- /dev/null
+/*
+ * 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 <unistd.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#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
/*
- * 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.
* 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 <stdbool.h>
+#include <sys/types.h>
-typedef int (*memory_monitor_cb)(bool low_memory, void *user_data);
+#include <string>
-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_