From 248b689cefbeec188522f6ba125ca8edfe7e3919 Mon Sep 17 00:00:00 2001 From: x00678224 Date: Sat, 20 May 2023 16:19:59 +0800 Subject: [PATCH] 0520 make pixelmap purgeable Signed-off-by: x00678224 Change-Id: Ice067a1e4ac2f02abb9f62e68b1e8b7318c665b3 --- bundle.json | 10 +- libpurgeablemem/BUILD.gn | 4 + .../cpp/include/purgeable_ashmem.h | 2 +- .../cpp/include/purgeable_mem_base.h | 3 +- .../cpp/include/purgeable_mem_builder.h | 7 + .../include/purgeable_resource_interface.h | 94 ++++++++++ .../cpp/include/purgeable_resource_manager.h | 161 ++++++++++++++++++ libpurgeablemem/cpp/src/purgeable_ashmem.cpp | 4 +- .../cpp/src/purgeable_resource_manager.cpp | 145 ++++++++++++++++ libpurgeablemem/test/purgeable_cpp_test.cpp | 15 ++ libpurgeablemem/test/purgeableashmem_test.cpp | 15 ++ purgeable_mem_config.gni | 16 ++ 12 files changed, 471 insertions(+), 5 deletions(-) create mode 100644 libpurgeablemem/cpp/include/purgeable_resource_interface.h create mode 100644 libpurgeablemem/cpp/include/purgeable_resource_manager.h create mode 100644 libpurgeablemem/cpp/src/purgeable_resource_manager.cpp create mode 100644 purgeable_mem_config.gni diff --git a/bundle.json b/bundle.json index 25c4c15..7fa9ffa 100644 --- a/bundle.json +++ b/bundle.json @@ -42,9 +42,15 @@ "name": "//commonlibrary/memory_utils/libpurgeablemem:libpurgeablemem", "header": { "header_files": [ - "purgeable_mem_c.h" + "pm_log.h", + "pm_smartptr_util.h", + "purgeable_ashmem.h", + "purgeable_mem.h", + "purgeable_mem_base.h", + "purgeable_mem_builder.h", + "ux_page_table.h" ], - "header_base": "//commonlibrary/memory_utils/libpurgeablemem/c/include" + "header_base": "//commonlibrary/memory_utils/libpurgeablemem/cpp/include" } } ], diff --git a/libpurgeablemem/BUILD.gn b/libpurgeablemem/BUILD.gn index bec592f..406ba34 100644 --- a/libpurgeablemem/BUILD.gn +++ b/libpurgeablemem/BUILD.gn @@ -32,12 +32,16 @@ ohos_shared_library("libpurgeablemem") { "cpp/src/purgeable_mem.cpp", "cpp/src/purgeable_mem_base.cpp", "cpp/src/purgeable_mem_builder.cpp", + "cpp/src/purgeable_resource_manager.cpp", "cpp/src/ux_page_table.cpp", ] include_dirs = [ "include" ] external_deps = [ "c_utils:utils", + "hitrace_native:hitrace_meter", "hiviewdfx_hilog_native:libhilog", + "init:libbegetutil", + "ipc:ipc_core", ] public_configs = [ ":libpurgeable_config" ] subsystem_name = "commonlibrary" diff --git a/libpurgeablemem/cpp/include/purgeable_ashmem.h b/libpurgeablemem/cpp/include/purgeable_ashmem.h index bf5f78e..5f18ca4 100644 --- a/libpurgeablemem/cpp/include/purgeable_ashmem.h +++ b/libpurgeablemem/cpp/include/purgeable_ashmem.h @@ -50,7 +50,7 @@ public: ~PurgeableAshMem() override; int GetAshmemFd(); void ResizeData(size_t newSize) override; - void ChangeAshmemData(size_t size, int fd, void *data); + bool ChangeAshmemData(size_t size, int fd, void *data); protected: int ashmemFd_; int isSupport_; diff --git a/libpurgeablemem/cpp/include/purgeable_mem_base.h b/libpurgeablemem/cpp/include/purgeable_mem_base.h index 2c2a8e0..bd57943 100644 --- a/libpurgeablemem/cpp/include/purgeable_mem_base.h +++ b/libpurgeablemem/cpp/include/purgeable_mem_base.h @@ -99,6 +99,8 @@ public: PurgeableMemBase(PurgeableMemBase&&) noexcept = delete; PurgeableMemBase& operator = (PurgeableMemBase&&) noexcept = delete; + bool IfNeedRebuild_(); + protected: void *dataPtr_ = nullptr; size_t dataSizeInput_; @@ -106,7 +108,6 @@ protected: std::shared_mutex rwlock_; unsigned int buildDataCount_; bool BuildContent_(); - bool IfNeedRebuild_(); virtual bool Pin_(); virtual bool Unpin_(); virtual bool IsPurged_(); diff --git a/libpurgeablemem/cpp/include/purgeable_mem_builder.h b/libpurgeablemem/cpp/include/purgeable_mem_builder.h index 9a3fbf0..7a4956a 100644 --- a/libpurgeablemem/cpp/include/purgeable_mem_builder.h +++ b/libpurgeablemem/cpp/include/purgeable_mem_builder.h @@ -37,6 +37,13 @@ public: */ virtual bool Build(void *data, size_t size) = 0; + /* + * User should define how to get the metaDataSize of a PurgeableMem obj in this func. + * MetaData is used to rebuild purgeableMem. + * Return: the meta data size. + */ + virtual size_t GetMetaDataSize() = 0; + private: std::unique_ptr nextBuilder_ = nullptr; diff --git a/libpurgeablemem/cpp/include/purgeable_resource_interface.h b/libpurgeablemem/cpp/include/purgeable_resource_interface.h new file mode 100644 index 0000000..79c5e6a --- /dev/null +++ b/libpurgeablemem/cpp/include/purgeable_resource_interface.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_UTILS_MEMORY_LIBPURGEABLEMEM_CPP_INCLUDE_PURGEABLE_RESOURCE_INTERFACE_H +#define OHOS_UTILS_MEMORY_LIBPURGEABLEMEM_CPP_INCLUDE_PURGEABLE_RESOURCE_INTERFACE_H + +#include "hitrace_meter.h" +#include "pm_log.h" +#include "purgeable_ashmem.h" +#include "purgeable_mem_builder.h" + +namespace OHOS { +namespace PurgeableMem { +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "PurgeableResourceInterface" + +class PurgeableResourceInterface { +public: + /* + * BeginVisitPurgeableMem: begin visit the PurgeableMem obj. + * if the obj is present, this method will start accessing it by + * calling the obj's BeginRead() function. + */ + virtual uint32_t BeginVisitPurgeableMem() + { + return 0; + } + + /* + * EndVisitPurgeableMem: end visit the PurgeableMem obj. + * if the obj is present, this method will end accessing it by + * calling the obj's EndRead() function. + */ + virtual uint32_t EndVisitPurgeableMem() + { + return 0; + } + + /* + * SetPurgeable: set purgeable state of the PurgeableMem obj. + * Input: @flag: boolean type parameter, it's used to mark the purgeable state of the current obj. + */ + virtual void SetPurgeable(bool flag) + { + isPurgeable_ = flag; + } + + /* + * IsPurgeable: get purgeable state of the PurgeableMem obj. + * Return: boolean type parameter, it's used to mark the purgeable state of the current obj. + */ + virtual bool IsPurgeable() + { + return isPurgeable_; + } + + /* + * SetIsNeedAddResourceManager: set the state of the PurgeableMem obj is need to be managed by the resource manager. + * Input: @flag: boolean type parameter, it's used to mark the current obj is need to be managed by the resource manager. + */ + virtual void SetIsNeedAddResourceManager(bool flag) + { + isNeedAddResourceManager_ = flag; + } + + /* + * GetIsNeedAddResourceManager: get the state of the PurgeableMem obj is need to be managed by the resource manager. + * Return: boolean type parameter. + */ + virtual bool GetIsNeedAddResourceManager() + { + return isNeedAddResourceManager_; + } +protected: + bool isPurgeable_ = {false}; + bool isNeedAddResourceManager_ = {false}; +}; +} /* namespace PurgeableMem */ +} /* namespace OHOS */ +#endif /* OHOS_UTILS_MEMORY_LIBPURGEABLEMEM_CPP_INCLUDE_PURGEABLE_RESOURCE_INTERFACE_H */ diff --git a/libpurgeablemem/cpp/include/purgeable_resource_manager.h b/libpurgeablemem/cpp/include/purgeable_resource_manager.h new file mode 100644 index 0000000..75e61eb --- /dev/null +++ b/libpurgeablemem/cpp/include/purgeable_resource_manager.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_UTILS_MEMORY_LIBPURGEABLEMEM_CPP_INCLUDE_PURGEABLE_RESOURCE_MANAGER_H +#define OHOS_UTILS_MEMORY_LIBPURGEABLEMEM_CPP_INCLUDE_PURGEABLE_RESOURCE_MANAGER_H + +#include +#include +#include +#include + +#include "purgeable_resource_interface.h" +#include "thread_pool.h" + +namespace OHOS { +namespace PurgeableMem { +/* System parameter name */ +const std::string THREAD_POOL_TASK_NUMBER_SYS_NAME = "persist.commonlibrary.purgeable.threadpooltasknum"; +const std::string LRU_CACHE_CAPACITY_SYS_NAME = "persist.commonlibrary.purgeable.lrucachecapacity"; +/* Threadpool task number and lrucache capacity */ +constexpr int32_t THREAD_POOL_TASK_NUMBER = 8; +constexpr int32_t MIN_THREAD_POOL_TASK_NUMBER = 1; +constexpr int32_t MAX_THREAD_POOL_TASK_NUMBER = 20; +constexpr int32_t LRU_CACHE_CAPACITY = 100; +constexpr int32_t MIN_LRU_CACHE_CAPACITY = 1; +constexpr int32_t MAX_LRU_CACHE_CAPACITY = 200; + +class LruCache { +public: + int32_t lruCacheCapacity; + std::list resourcePtrList; + std::unordered_map::iterator> positionMap; + + /* + * Visited: visit the cache entry with the given key. + * If the entry is found, it will be move to the most-recent position in the cache. + */ + void Visited(PurgeableResourceInterface *key) + { + if (key == nullptr) { + return; + } + + auto resourcePtrIndex = positionMap.find((long) key); + if(resourcePtrIndex != positionMap.end()) { + resourcePtrList.splice(resourcePtrList.begin(), resourcePtrList, resourcePtrIndex->second); + return; + } + + return; + } + + /* + * Put: put the PurgeableResourceInterface key in the lrucache. + * Input: @key: ptr of PurgeableResourceInterface. + */ + void Put(PurgeableResourceInterface *key) + { + if (key == nullptr) { + return; + } + + auto resourcePtrIndex = positionMap.find((long) key); + if(resourcePtrIndex != positionMap.end()) { + resourcePtrList.splice(resourcePtrList.begin(), resourcePtrList, resourcePtrIndex->second); + return; + } + + resourcePtrList.emplace_front(key); + positionMap.emplace((long) key, resourcePtrList.begin()); + + if (static_cast(resourcePtrList.size()) > lruCacheCapacity) { + positionMap.erase((long) resourcePtrList.back()); + resourcePtrList.pop_back(); + } + return; + } + + /* + * Erase: erase the PurgeableResourceInterface key in the lrucache. + * Input: @key: ptr of PurgeableResourceInterface. + */ + void Erase(PurgeableResourceInterface *key) + { + if (key == nullptr) { + return; + } + + auto resourcePtrIndex = positionMap.find((long) key); + if(resourcePtrIndex == positionMap.end()) { + return; + } + + resourcePtrList.erase(resourcePtrIndex->second); + positionMap.erase((long) key); + return; + } + + /* + * SetCapacity: set the capacity of the lrucache. + * Input: the capacity of lrucache. + */ + void SetCapacity(int32_t capacity) + { + lruCacheCapacity = capacity; + } + + /* + * Clear: clear the resourcePtrList and positionMap of the lrucache. + */ + void Clear() + { + positionMap.clear(); + resourcePtrList.clear(); + } +}; + +class PurgeableResourceManager { +public: + PurgeableResourceManager() + { + GetParaFromConfiguration(); + } + + ~PurgeableResourceManager() + { + threadPool_.Stop(); + lruCache_.Clear(); + } + + static PurgeableResourceManager &GetInstance(); + void ExecBeginVisitPurgeableMem(); + void ExecEndVisitPurgeableMem(); + void AddResource(PurgeableResourceInterface *); + void RemoveResource(PurgeableResourceInterface *); + void SetRecentUsedResource(PurgeableResourceInterface *); + int32_t GetThreadPoolTaskNumFromSysPara(); + int32_t GetLruCacheCapacityFromSysPara(); + void GetParaFromConfiguration(); + +private: + std::mutex mutex_; + LruCache lruCache_; + ThreadPool threadPool_; +}; + +} /* namespace PurgeableMem */ +} /* namespace OHOS */ +#endif /* OHOS_UTILS_MEMORY_LIBPURGEABLEMEM_CPP_INCLUDE_PURGEABLE_RESOURCE_MANAGER_H */ diff --git a/libpurgeablemem/cpp/src/purgeable_ashmem.cpp b/libpurgeablemem/cpp/src/purgeable_ashmem.cpp index 8462ce2..ea607fe 100644 --- a/libpurgeablemem/cpp/src/purgeable_ashmem.cpp +++ b/libpurgeablemem/cpp/src/purgeable_ashmem.cpp @@ -187,11 +187,12 @@ void PurgeableAshMem::ResizeData(size_t newSize) CreatePurgeableData_(); } -void PurgeableAshMem::ChangeAshmemData(size_t size, int fd, void *data) +bool PurgeableAshMem::ChangeAshmemData(size_t size, int fd, void *data) { if (dataPtr_) { if (munmap(dataPtr_, RoundUp_(dataSizeInput_, PAGE_SIZE)) != 0) { PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__); + return false; } else { dataPtr_ = nullptr; if (ashmemFd_ > 0) { @@ -208,6 +209,7 @@ void PurgeableAshMem::ChangeAshmemData(size_t size, int fd, void *data) isSupport_ = true; } Unpin_(); + return true; } inline std::string PurgeableAshMem::ToString_() const diff --git a/libpurgeablemem/cpp/src/purgeable_resource_manager.cpp b/libpurgeablemem/cpp/src/purgeable_resource_manager.cpp new file mode 100644 index 0000000..f7b2904 --- /dev/null +++ b/libpurgeablemem/cpp/src/purgeable_resource_manager.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 +#include + +#include "hitrace_meter.h" +#include "parameters.h" +#include "pm_log.h" +#include "purgeable_resource_manager.h" + + +namespace OHOS { +namespace PurgeableMem { + +PurgeableResourceManager &PurgeableResourceManager::GetInstance() +{ + static PurgeableResourceManager instance; + return instance; +} + +void PurgeableResourceManager::ExecBeginVisitPurgeableMem() +{ + std::lock_guard lock(mutex_); + StartTrace(HITRACE_TAG_COMMONLIBRARY, "PurgeableResourceManager::ExecBeginVisitPurgeableMem"); + for (auto &resourcePtr : lruCache_.resourcePtrList) { + if (resourcePtr == nullptr) { + continue; + } + + auto task = std::bind(&PurgeableResourceInterface::BeginVisitPurgeableMem, (PurgeableResourceInterface *) resourcePtr); + threadPool_.AddTask(task); + } + + FinishTrace(HITRACE_TAG_COMMONLIBRARY); + PM_HILOG_DEBUG(LOG_CORE, "[PurgeableResourceManager] ExecBeginVisitPurgeableMem list size: %{public}zu", + lruCache_.resourcePtrList.size()); + return; +} + +void PurgeableResourceManager::ExecEndVisitPurgeableMem() +{ + std::lock_guard lock(mutex_); + StartTrace(HITRACE_TAG_COMMONLIBRARY, "PurgeableResourceManager::ExecUnPin"); + for (auto &resourcePtr : lruCache_.resourcePtrList) { + if (resourcePtr == nullptr) { + continue; + } + + auto task = std::bind(&PurgeableResourceInterface::EndVisitPurgeableMem, (PurgeableResourceInterface *) resourcePtr); + threadPool_.AddTask(task); + } + + FinishTrace(HITRACE_TAG_COMMONLIBRARY); + PM_HILOG_DEBUG(LOG_CORE, "[PurgeableResourceManager] ExecUnPin list size: %{public}zu", + lruCache_.resourcePtrList.size()); + return; +} + +void PurgeableResourceManager::AddResource(PurgeableResourceInterface *resourcePtr) +{ + std::lock_guard lock(mutex_); + StartTrace(HITRACE_TAG_COMMONLIBRARY, "PurgeableResourceManager::AddResource"); + if (resourcePtr == nullptr) { + return; + } + + lruCache_.Put(resourcePtr); + FinishTrace(HITRACE_TAG_COMMONLIBRARY); + PM_HILOG_DEBUG(LOG_CORE, "[PurgeableResourceManager] AddResource list size: %{public}zu", + lruCache_.resourcePtrList.size()); +} + +void PurgeableResourceManager::RemoveResource(PurgeableResourceInterface *resourcePtr) +{ + std::lock_guard lock(mutex_); + StartTrace(HITRACE_TAG_COMMONLIBRARY, "PurgeableResourceManager::RemoveResource"); + if (resourcePtr == nullptr) { + return; + } + + lruCache_.Erase(resourcePtr); + FinishTrace(HITRACE_TAG_COMMONLIBRARY); + PM_HILOG_DEBUG(LOG_CORE, "[PurgeableResourceManager] RemoveResource list size: %{public}zu", + lruCache_.resourcePtrList.size()); +} + +void PurgeableResourceManager::SetRecentUsedResource(PurgeableResourceInterface *resourcePtr) +{ + std::lock_guard lock(mutex_); + if (resourcePtr == nullptr) { + return; + } + + lruCache_.Visited(resourcePtr); +} + +int32_t PurgeableResourceManager::GetThreadPoolTaskNumFromSysPara() +{ + return system::GetIntParameter(THREAD_POOL_TASK_NUMBER_SYS_NAME, THREAD_POOL_TASK_NUMBER); +} + +int32_t PurgeableResourceManager::GetLruCacheCapacityFromSysPara() +{ + return system::GetIntParameter(LRU_CACHE_CAPACITY_SYS_NAME, LRU_CACHE_CAPACITY); +} + +void PurgeableResourceManager::GetParaFromConfiguration() +{ + int32_t threadPoolTaskNum = GetThreadPoolTaskNumFromSysPara(); + int32_t lruCacheCapacity = GetLruCacheCapacityFromSysPara(); + if (threadPoolTaskNum < MIN_THREAD_POOL_TASK_NUMBER || threadPoolTaskNum > MAX_THREAD_POOL_TASK_NUMBER) { + PM_HILOG_ERROR(LOG_CORE, "[PurgeableResourceManager] Get error threadpool task number from system parameter."); + return; + } + + if (lruCacheCapacity < MIN_LRU_CACHE_CAPACITY || lruCacheCapacity > MAX_LRU_CACHE_CAPACITY) { + PM_HILOG_ERROR(LOG_CORE, "[PurgeableResourceManager] Get error lrucache capacity from system parameter."); + return; + } + + lruCache_.SetCapacity(lruCacheCapacity); + if (threadPool_.GetThreadsNum() == 0) { + threadPool_.Start(threadPoolTaskNum); + } + + PM_HILOG_DEBUG(LOG_CORE, "[PurgeableResourceManager] lruCacheCapacity is: %{public}d", + lruCacheCapacity); + PM_HILOG_DEBUG(LOG_CORE, "[PurgeableResourceManager] threadPool threadsNum is: %{public}zu", + threadPool_.GetThreadsNum()); +} +} /* namespace PurgeableMem */ +} /* namespace OHOS */ diff --git a/libpurgeablemem/test/purgeable_cpp_test.cpp b/libpurgeablemem/test/purgeable_cpp_test.cpp index c23f675..8c5c112 100644 --- a/libpurgeablemem/test/purgeable_cpp_test.cpp +++ b/libpurgeablemem/test/purgeable_cpp_test.cpp @@ -57,6 +57,11 @@ public: return true; } + size_t GetMetaDataSize() + { + return 0; + } + ~TestDataBuilder() { std::cout << "~TestDataBuilder" << std::endl; @@ -85,6 +90,11 @@ public: return true; } + size_t GetMetaDataSize() + { + return 0; + } + ~TestDataModifier() { std::cout << "~TestDataModifier" << std::endl; @@ -115,6 +125,11 @@ public: return true; } + size_t GetMetaDataSize() + { + return 0; + } + ~TestBigDataBuilder() { std::cout << "~TestBigDataBuilder" << std::endl; diff --git a/libpurgeablemem/test/purgeableashmem_test.cpp b/libpurgeablemem/test/purgeableashmem_test.cpp index fc1a95d..0f398de 100644 --- a/libpurgeablemem/test/purgeableashmem_test.cpp +++ b/libpurgeablemem/test/purgeableashmem_test.cpp @@ -64,6 +64,11 @@ public: return true; } + size_t GetMetaDataSize() + { + return 0; + } + ~TestDataBuilder() { std::cout << "~TestDataBuilder" << std::endl; @@ -92,6 +97,11 @@ public: return true; } + size_t GetMetaDataSize() + { + return 0; + } + ~TestDataModifier() { std::cout << "~TestDataModifier" << std::endl; @@ -122,6 +132,11 @@ public: return true; } + size_t GetMetaDataSize() + { + return 0; + } + ~TestBigDataBuilder() { std::cout << "~TestBigDataBuilder" << std::endl; diff --git a/purgeable_mem_config.gni b/purgeable_mem_config.gni new file mode 100644 index 0000000..388025d --- /dev/null +++ b/purgeable_mem_config.gni @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# 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. + +declare_args() { + purgeable_ashmem_enable = false +} -- Gitee