• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "memory/rs_memory_snapshot.h"
16 
17 #include "platform/common/rs_log.h"
18 
19 namespace OHOS {
20 namespace Rosen {
21 namespace {
22 constexpr uint32_t MEMUNIT_RATE = 1024;
23 constexpr int64_t MEMORY_SNAPSHOT_INTERVAL = 3 * 60 * 1000; // EachProcess can print at most once per 3 minute.
24 // Threshold for hilog in rs mem.
25 constexpr uint32_t MEMORY_SNAPSHOT_PRINT_HILOG_LIMIT = 1300 * MEMUNIT_RATE * MEMUNIT_RATE;
26 constexpr uint32_t HILOG_INFO_COUNT = 5; // The number of info printed each time.
27 constexpr float WEIGHT_CPU = 0.3; // Weight of CPU.
28 constexpr float WEIGHT_GPU = 0.3; // Weight of GPU.
29 constexpr float WEIGHT_SUM = 0.4; // Weight of CPU+GPU.
30 }
31 
Instance()32 MemorySnapshot& MemorySnapshot::Instance()
33 {
34     static MemorySnapshot instance;
35     return instance;
36 }
37 
AddCpuMemory(const pid_t pid,const size_t size)38 void MemorySnapshot::AddCpuMemory(const pid_t pid, const size_t size)
39 {
40     std::lock_guard<std::mutex> lock(mutex_);
41     if (appMemorySnapshots_.find(pid) == appMemorySnapshots_.end()) {
42         dirtyMemorySnapshots_.push_back(pid);
43     }
44 
45     MemorySnapshotInfo& mInfo = appMemorySnapshots_[pid];
46     mInfo.pid = pid;
47     mInfo.cpuMemory += size;
48 }
49 
RemoveCpuMemory(const pid_t pid,const size_t size)50 void MemorySnapshot::RemoveCpuMemory(const pid_t pid, const size_t size)
51 {
52     std::lock_guard<std::mutex> lock(mutex_);
53     auto it = appMemorySnapshots_.find(pid);
54     if (it != appMemorySnapshots_.end()) {
55         if (it->second.cpuMemory >= size) {
56             it->second.cpuMemory -= size;
57         }
58     }
59 }
60 
GetMemorySnapshotInfoByPid(const pid_t pid,MemorySnapshotInfo & info)61 bool MemorySnapshot::GetMemorySnapshotInfoByPid(const pid_t pid, MemorySnapshotInfo& info)
62 {
63     std::lock_guard<std::mutex> lock(mutex_);
64     auto it = appMemorySnapshots_.find(pid);
65     if (it == appMemorySnapshots_.end()) {
66         return false;
67     }
68     info = it->second;
69     return true;
70 }
71 
UpdateGpuMemoryInfo(const std::unordered_map<pid_t,size_t> & uniRenderGpuInfo,const std::unordered_map<pid_t,size_t> & subThreadGpuInfo,std::unordered_map<pid_t,MemorySnapshotInfo> & pidForReport,bool & isTotalOver)72 void MemorySnapshot::UpdateGpuMemoryInfo(const std::unordered_map<pid_t, size_t>& uniRenderGpuInfo,
73     const std::unordered_map<pid_t, size_t>& subThreadGpuInfo,
74     std::unordered_map<pid_t, MemorySnapshotInfo>& pidForReport, bool& isTotalOver)
75 {
76     std::lock_guard<std::mutex> lock(mutex_);
77     for (auto& [pid, info] : appMemorySnapshots_) {
78         auto it = uniRenderGpuInfo.find(pid);
79         if (it != uniRenderGpuInfo.end()) {
80             totalMemory_ = totalMemory_ - info.gpuMemory + it->second;
81             info.gpuMemory = it->second;
82         }
83         auto subThreadInfoIt = subThreadGpuInfo.find(pid);
84         if (subThreadInfoIt != subThreadGpuInfo.end()) {
85             totalMemory_ = totalMemory_ - info.subThreadGpuMemory + subThreadInfoIt->second;
86             info.subThreadGpuMemory = subThreadInfoIt->second;
87         }
88         if (info.TotalMemory() > singleMemoryWarning_) {
89             pidForReport.emplace(pid, info);
90         }
91     }
92     if (totalMemory_ > totalMemoryLimit_) {
93         pidForReport = appMemorySnapshots_;
94         isTotalOver = true;
95     }
96     if (memSnapshotPrintHilogLimit_ > 0) {
97         if (totalMemory_ > memSnapshotPrintHilogLimit_) {
98             PrintMemorySnapshotToHilog();
99         }
100     } else {
101         if (totalMemory_ > MEMORY_SNAPSHOT_PRINT_HILOG_LIMIT) {
102             PrintMemorySnapshotToHilog();
103         }
104     }
105 }
106 
SetMemSnapshotPrintHilogLimit(int memSnapshotPrintHilogLimit)107 void MemorySnapshot::SetMemSnapshotPrintHilogLimit(int memSnapshotPrintHilogLimit)
108 {
109     memSnapshotPrintHilogLimit_ = memSnapshotPrintHilogLimit * MEMUNIT_RATE * MEMUNIT_RATE;
110 }
111 
GetMemSnapshotPrintHilogLimit()112 int MemorySnapshot::GetMemSnapshotPrintHilogLimit()
113 {
114     return memSnapshotPrintHilogLimit_;
115 }
116 
117 
EraseSnapshotInfoByPid(const std::set<pid_t> & exitedPidSet)118 void MemorySnapshot::EraseSnapshotInfoByPid(const std::set<pid_t>& exitedPidSet)
119 {
120     std::lock_guard<std::mutex> lock(mutex_);
121     for (auto pid : exitedPidSet) {
122         auto it = appMemorySnapshots_.find(pid);
123         if (it != appMemorySnapshots_.end()) {
124             totalMemory_ -= it->second.gpuMemory;
125             appMemorySnapshots_.erase(it);
126         }
127     }
128 }
129 
InitMemoryLimit(MemoryOverflowCalllback callback,uint64_t warning,uint64_t overflow,uint64_t totalSize)130 void MemorySnapshot::InitMemoryLimit(MemoryOverflowCalllback callback,
131     uint64_t warning, uint64_t overflow, uint64_t totalSize)
132 {
133     if (callback_ == nullptr) {
134         callback_ = callback;
135         singleMemoryWarning_ = warning;
136         singleCpuMemoryLimit_ = overflow;
137         totalMemoryLimit_ = totalSize;
138     }
139 }
140 
GetMemorySnapshot(std::unordered_map<pid_t,MemorySnapshotInfo> & map)141 void MemorySnapshot::GetMemorySnapshot(std::unordered_map<pid_t, MemorySnapshotInfo>& map)
142 {
143     std::lock_guard<std::mutex> lock(mutex_);
144     map = appMemorySnapshots_;
145 }
146 
GetDirtyMemorySnapshot(std::vector<pid_t> & list)147 void MemorySnapshot::GetDirtyMemorySnapshot(std::vector<pid_t>& list)
148 {
149     std::lock_guard<std::mutex> lock(mutex_);
150     list = dirtyMemorySnapshots_;
151 }
152 
FillMemorySnapshot(std::unordered_map<pid_t,MemorySnapshotInfo> & infoMap)153 void MemorySnapshot::FillMemorySnapshot(std::unordered_map<pid_t, MemorySnapshotInfo>& infoMap)
154 {
155     std::lock_guard<std::mutex> lock(mutex_);
156     for (auto pPid = dirtyMemorySnapshots_.begin(); pPid != dirtyMemorySnapshots_.end();) {
157         auto it = appMemorySnapshots_.find(*pPid);
158         if (it != appMemorySnapshots_.end()) {
159             it->second.bundleName = infoMap[it->first].bundleName;
160             it->second.uid = infoMap[it->first].uid;
161         }
162         pPid = dirtyMemorySnapshots_.erase(pPid);
163     }
164 }
165 
GetTotalMemory()166 size_t MemorySnapshot::GetTotalMemory()
167 {
168     return totalMemory_;
169 }
170 
PrintMemorySnapshotToHilog()171 void MemorySnapshot::PrintMemorySnapshotToHilog()
172 {
173     auto now = std::chrono::steady_clock::now().time_since_epoch();
174     int64_t currentTime = std::chrono::duration_cast<std::chrono::milliseconds>(now).count();
175     if (currentTime < memorySnapshotHilogTime_) {
176         return;
177     }
178 
179     std::vector<MemorySnapshotInfo> memorySnapshotsList;
180     size_t maxCpu;
181     size_t maxGpu;
182     size_t maxSum;
183     FindMaxValues(memorySnapshotsList, maxCpu, maxGpu, maxSum);
184 
185     // Sort by risk in descending order
186     std::sort(memorySnapshotsList.begin(), memorySnapshotsList.end(),
187         [=](const MemorySnapshotInfo& a, const MemorySnapshotInfo& b) {
188             float scoreA = CalculateRiskScore(a, maxCpu, maxGpu, maxSum);
189             float scoreB = CalculateRiskScore(b, maxCpu, maxGpu, maxSum);
190             return scoreA > scoreB;
191         });
192 
193     RS_LOGE("TotalMemoryOverReport. TotalMemory:[%{public}zuKB]", totalMemory_ / MEMUNIT_RATE);
194     for (size_t i = 0 ; i < HILOG_INFO_COUNT && i < memorySnapshotsList.size() ; i++) {
195         MemorySnapshotInfo info = memorySnapshotsList[i];
196         RS_LOGE("pid : %{public}d %{public}s, cpu : %{public}zuKB, gpu : %{public}zuKB",
197             static_cast<int32_t>(info.pid), info.bundleName.c_str(),
198             info.cpuMemory / MEMUNIT_RATE, (info.gpuMemory + info.subThreadGpuMemory) / MEMUNIT_RATE);
199     }
200 
201     memorySnapshotHilogTime_ = currentTime + MEMORY_SNAPSHOT_INTERVAL;
202 }
203 
FindMaxValues(std::vector<MemorySnapshotInfo> & memorySnapshotsList,size_t & maxCpu,size_t & maxGpu,size_t & maxSum)204 void MemorySnapshot::FindMaxValues(std::vector<MemorySnapshotInfo>& memorySnapshotsList,
205     size_t& maxCpu, size_t& maxGpu, size_t& maxSum)
206 {
207     maxCpu = maxGpu = maxSum = 0;
208     for (const auto& [pid, snapshotInfo] : appMemorySnapshots_) {
209         memorySnapshotsList.push_back(snapshotInfo);
210 
211         if (snapshotInfo.cpuMemory > maxCpu) {
212             maxCpu = snapshotInfo.cpuMemory;
213         }
214 
215         if (snapshotInfo.gpuMemory + snapshotInfo.subThreadGpuMemory > maxGpu) {
216             maxGpu = snapshotInfo.gpuMemory + snapshotInfo.subThreadGpuMemory;
217         }
218 
219         size_t totalMemory = snapshotInfo.TotalMemory();
220         if (totalMemory > maxSum) {
221             maxSum = totalMemory;
222         }
223     }
224 }
225 
CalculateRiskScore(const MemorySnapshotInfo snapshotInfo,size_t maxCpu,size_t maxGpu,size_t maxSum)226 float MemorySnapshot::CalculateRiskScore(const MemorySnapshotInfo snapshotInfo,
227     size_t maxCpu, size_t maxGpu, size_t maxSum)
228 {
229     float normCpu = (maxCpu == 0) ? 0 : static_cast<float>(snapshotInfo.cpuMemory) / maxCpu;
230     float normGpu =
231         (maxGpu == 0) ? 0 : static_cast<float>(snapshotInfo.gpuMemory + snapshotInfo.subThreadGpuMemory) / maxGpu;
232     float normSum = (maxSum == 0) ? 0 : static_cast<float>(snapshotInfo.TotalMemory()) / maxSum;
233     return WEIGHT_CPU * normCpu + WEIGHT_GPU * normGpu + WEIGHT_SUM * normSum;
234 }
235 }
236 } // namespace OHOS::Rosen