• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "purgeable_mem_utils.h"
17 
18 #include <unordered_map>
19 
20 #include "kernel_interface.h"
21 #include "memmgr_log.h"
22 
23 namespace OHOS {
24 namespace Memory {
25 namespace {
26 const std::string TAG = "PurgeableMemUtils";
27 }
28 
29 IMPLEMENT_SINGLE_INSTANCE(PurgeableMemUtils);
30 
31 const std::string PurgeableMemUtils::PATH_PURGE_HEAP = "/proc/sys/kernel/purgeable";
32 const std::string PurgeableMemUtils::PATH_PURGEABLE_ASHMEM = "/proc/purgeable_ashmem_trigger";
33 const std::string PurgeableMemUtils::FILE_PURGE_MEMCG_HEAP = "memory.force_shrink_purgeable_bysize";
34 const std::string PurgeableMemUtils::ACTIVE_PURGEABLE_HEAP = "Active(purg):";
35 const std::string PurgeableMemUtils::INACTIVE_PURGEABLE_HEAP = "Inactive(purg):";
36 const std::string PurgeableMemUtils::PINED_PURGEABLE_HEAP = "Pined(purg):";
37 const std::string PurgeableMemUtils::PROC_PURGEABLE_HEAP = "PurgSum:";
38 const std::string PurgeableMemUtils::PROC_PINED_PURGEABLE_HEAP = "PurgPin:";
39 const unsigned int PurgeableMemUtils::ASHM_PARAM_SIZE_ONE_LINE = 10;
40 const unsigned int PurgeableMemUtils::ASHM_ID_INDEX = 6;
41 const unsigned int PurgeableMemUtils::ASHM_ADJ_INDEX = 2;
42 const unsigned int PurgeableMemUtils::ASHM_REF_COUNT_INDEX = 8;
43 const unsigned int PurgeableMemUtils::ASHM_PURGED_INDEX = 9;
44 const unsigned int PurgeableMemUtils::ASHM_SIZE_INDEX = 5;
45 const unsigned int PurgeableMemUtils::ASHM_TIME_INDEX = 7;
46 const unsigned int PurgeableMemUtils::HEAPINFO_SIZE_ONE_LINE = 3;
47 
GetPurgeableHeapInfo(int & reclaimableKB)48 bool PurgeableMemUtils::GetPurgeableHeapInfo(int &reclaimableKB)
49 {
50     std::vector<std::string> strLines;
51     if (!KernelInterface::GetInstance().ReadLinesFromFile(KernelInterface::MEMINFO_PATH, strLines)) {
52         HILOGE("read file and split to lines failed : %{public}s", KernelInterface::MEMINFO_PATH.c_str());
53         return false;
54     }
55 
56     int activeKB = -1;
57     int inactiveKB = -1;
58     int pinedKB = -1;
59     for (auto &it : strLines) {
60         std::vector<std::string> words;
61         KernelInterface::GetInstance().SplitOneLineByBlank(it, words);
62         if (words.size() != HEAPINFO_SIZE_ONE_LINE) {
63             continue;
64         }
65         try {
66             if (words[0] == ACTIVE_PURGEABLE_HEAP) {
67                 activeKB = stoi(words[1]);
68             } else if (words[0] == INACTIVE_PURGEABLE_HEAP) {
69                 inactiveKB = stoi(words[1]);
70             } else if (words[0] == PINED_PURGEABLE_HEAP) {
71                 pinedKB = stoi(words[1]);
72             }
73         } catch (...) {
74             HILOGE("stoi(%{public}s) failed", words[1].c_str());
75             return false;
76         }
77     }
78 
79     reclaimableKB = activeKB + inactiveKB - pinedKB;
80     if (activeKB >= 0 && inactiveKB >= 0 && pinedKB >= 0 && reclaimableKB >= 0) {
81         return true;
82     }
83     return false;
84 }
85 
GetProcPurgeableHeapInfo(const int pid,int & reclaimableKB)86 bool PurgeableMemUtils::GetProcPurgeableHeapInfo(const int pid, int &reclaimableKB)
87 {
88     std::string path = KernelInterface::GetInstance().JoinPath(KernelInterface::ROOT_PROC_PATH, std::to_string(pid),
89                                                                KernelInterface::FILE_PROC_STATUS);
90     std::vector<std::string> strLines;
91     if (!KernelInterface::GetInstance().ReadLinesFromFile(path, strLines)) {
92         HILOGE("read file and split to lines failed : %{public}s", path.c_str());
93         return false;
94     }
95 
96     int purgSumKB = -1;
97     int purgPinKB = -1;
98     for (auto &it : strLines) {
99         std::vector<std::string> words;
100         KernelInterface::GetInstance().SplitOneLineByBlank(it, words);
101         if (words.size() != HEAPINFO_SIZE_ONE_LINE) {
102             continue;
103         }
104         try {
105             if (words[0] == PROC_PURGEABLE_HEAP) {
106                 purgSumKB = stoi(words[1]);
107             } else if (words[0] == PROC_PINED_PURGEABLE_HEAP) {
108                 purgPinKB = stoi(words[1]);
109             }
110         } catch (...) {
111             HILOGE("stoi(%{public}s) failed", words[1].c_str());
112             return false;
113         }
114     }
115 
116     reclaimableKB = purgSumKB - purgPinKB;
117     if (purgSumKB >= 0 && purgPinKB >= 0 && reclaimableKB >= 0) {
118         return true;
119     }
120     return false;
121 }
122 
PurgeHeapAll()123 bool PurgeableMemUtils::PurgeHeapAll()
124 {
125     HILOGD("enter! Purg heap memory all");
126     return KernelInterface::GetInstance().EchoToPath(PATH_PURGE_HEAP.c_str(), "1");
127 }
128 
PurgeHeapMemcg(const std::string & memcgPath,const int sizeKB)129 bool PurgeableMemUtils::PurgeHeapMemcg(const std::string &memcgPath, const int sizeKB)
130 {
131     std::string path = KernelInterface::GetInstance().JoinPath(memcgPath, FILE_PURGE_MEMCG_HEAP);
132     HILOGD("enter! Purg heap memory by memcg: size=%{public}d, path=%{public}s\n", sizeKB, path.c_str());
133     return KernelInterface::GetInstance().EchoToPath(path.c_str(), std::to_string(sizeKB).c_str());
134 }
135 
GetPurgeableAshmInfo(int & reclaimableKB,std::vector<PurgeableAshmInfo> & ashmInfoToReclaim)136 bool PurgeableMemUtils::GetPurgeableAshmInfo(int &reclaimableKB, std::vector<PurgeableAshmInfo> &ashmInfoToReclaim)
137 {
138     std::vector<std::string> strLines;
139     if (!KernelInterface::GetInstance().ReadLinesFromFile(PATH_PURGEABLE_ASHMEM, strLines)) {
140         HILOGE("read file and split to lines failed : %{public}s", PATH_PURGEABLE_ASHMEM.c_str());
141         return false;
142     }
143 
144     std::unordered_map<std::string, PurgeableAshmInfo> ashmIdToInfoMap;
145     for (auto &it : strLines) {
146         HILOGD("[ASHM]: %{public}s", it.c_str());
147         std::vector<std::string> words;
148         KernelInterface::GetInstance().SplitOneLineByDelim(it, ',', words);
149         if (words.size() != ASHM_PARAM_SIZE_ONE_LINE || words[ASHM_REF_COUNT_INDEX] != "0" ||
150             words[ASHM_PURGED_INDEX] != "0") {
151             continue;
152         }
153         int minPriority;
154         int sizeKB;
155         try {
156             minPriority = stoi(words[ASHM_ADJ_INDEX]);
157             sizeKB = stoi(words[ASHM_SIZE_INDEX]);
158         } catch (...) {
159             HILOGE("stoi(%{public}s) or stoi(%{public}s) failed", words[ASHM_ADJ_INDEX].c_str(),
160                 words[ASHM_SIZE_INDEX].c_str());
161             continue;
162         }
163         std::string key = words[ASHM_ID_INDEX] + std::string(" ") + words[ASHM_TIME_INDEX];
164         auto iter = ashmIdToInfoMap.find(key);
165         if (iter == ashmIdToInfoMap.end()) {
166             PurgeableAshmInfo info;
167             info.minPriority = minPriority;
168             info.sizeKB = sizeKB;
169             info.idWithTime = key;
170             ashmIdToInfoMap[key] = info;
171         } else if (iter->second.minPriority > minPriority) {
172             iter->second.minPriority = minPriority;
173         }
174     }
175 
176     reclaimableKB = 0;
177     ashmInfoToReclaim.clear();
178     for (const auto &[_1, value] : ashmIdToInfoMap) {
179         if (value.sizeKB > 0) {
180             ashmInfoToReclaim.emplace_back(value);
181             reclaimableKB += value.sizeKB;
182         }
183     }
184     HILOGD("there are %{public}dKB reclaimable purgeable [ASHM], ashmInfoVector.size()=%{public}zu", reclaimableKB,
185            ashmInfoToReclaim.size());
186     return true;
187 }
188 
PurgeAshmAll()189 bool PurgeableMemUtils::PurgeAshmAll()
190 {
191     HILOGD("enter! Purg ashmem memory all");
192     return KernelInterface::GetInstance().EchoToPath(PATH_PURGEABLE_ASHMEM.c_str(), "0 0");
193 }
194 
PurgeAshmByIdWithTime(const std::string & idWithTime)195 bool PurgeableMemUtils::PurgeAshmByIdWithTime(const std::string &idWithTime)
196 {
197     HILOGD("enter! Purg ashmem memory: IdWithTime=%{public}s", idWithTime.c_str());
198     return KernelInterface::GetInstance().EchoToPath(PATH_PURGEABLE_ASHMEM.c_str(), idWithTime.c_str());
199 }
200 } // namespace Memory
201 } // namespace OHOS
202