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