1/*
2 * Copyright (C) 2021 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 "include/RAM.h"
16#include <sstream>
17#include <fstream>
18#include <climits>
19#include <cstdio>
20#include <algorithm>
21#include <iostream>
22#include <thread>
23#include <string>
24#include <regex>
25#include "include/sp_utils.h"
26#include "memory_collector.h"
27#include "collect_result.h"
28#include "include/startup_delay.h"
29#include "include/sp_log.h"
30#include "include/common.h"
31
32using namespace OHOS::HiviewDFX;
33using namespace OHOS::HiviewDFX::UCollectUtil;
34using namespace OHOS::HiviewDFX::UCollect;
35
36namespace OHOS {
37namespace SmartPerf {
38bool g_flagFirst = false;
39std::map<std::string, std::string> procRamInfoLast {
40    {"pss", "NA"},
41    {"gpuPss", "NA"},
42    {"graphicPss", "NA"},
43    {"arktsHeapPss", "NA"},
44    {"nativeHeapPss", "NA"},
45    {"stackPss", "NA"},
46    {"sharedClean", "NA"},
47    {"sharedDirty", "NA"},
48    {"privateClean", "NA"},
49    {"privateDirty", "NA"},
50    {"swap", "NA"},
51    {"swapPss", "NA"},
52    {"heapSize", "NA"},
53    {"heapAlloc", "NA"},
54    {"heapFree", "NA"},
55};
56std::map<std::string, std::string> RAM::ItemData()
57{
58    std::map<std::string, std::string> result;
59    std::map<std::string, std::string> sysRamInfo = RAM::GetSysRamInfo();
60    for (auto it = sysRamInfo.begin(); it != sysRamInfo.end(); ++it) {
61        result.insert(*it);
62    }
63    if (!processId.empty()) {
64        if (g_flagFirst) {
65            RAM::TriggerGetPss();
66        } else {
67            procRamInfoLast = RAM::GetRamInfo();
68            g_flagFirst = true;
69        }
70        for (auto it = procRamInfoLast.begin(); it != procRamInfoLast.end(); ++it) {
71            result.insert(*it);
72        }
73    } else if (!packageName.empty() && processId.empty()) {
74        std::map<std::string, std::string> procMemInfo = RAM::ProcMemNaInfo();
75        for (auto it = procMemInfo.begin(); it != procMemInfo.end(); ++it) {
76            result.insert(*it);
77        }
78    }
79    LOGI("RAM::ItemData map size(%u)", result.size());
80    return result;
81}
82
83void RAM::ThreadGetPss() const
84{
85    std::map<std::string, std::string> procRamInfo = RAM::GetRamInfo();
86    procRamInfoLast = procRamInfo;
87}
88
89void RAM::TriggerGetPss() const
90{
91    auto tStart = std::thread([this]() {
92        this->ThreadGetPss();
93    });
94    tStart.detach();
95}
96
97void RAM::SetFirstFlag()
98{
99    g_flagFirst = false;
100}
101
102std::map<std::string, std::string> RAM::ProcMemNaInfo() const
103{
104    std::map<std::string, std::string> procMemInfo;
105    procMemInfo["arktsHeapPss"] = "NA";
106    procMemInfo["gpuPss"] = "NA";
107    procMemInfo["graphicPss"] = "NA";
108    procMemInfo["heapAlloc"] = "NA";
109    procMemInfo["heapFree"] = "NA";
110    procMemInfo["heapSize"] = "NA";
111    procMemInfo["nativeHeapPss"] = "NA";
112    procMemInfo["privateClean"] = "NA";
113    procMemInfo["privateDirty"] = "NA";
114    procMemInfo["pss"] = "NA";
115    procMemInfo["sharedClean"] = "NA";
116    procMemInfo["sharedDirty"] = "NA";
117    procMemInfo["stackPss"] = "NA";
118    procMemInfo["swap"] = "NA";
119    procMemInfo["swapPss"] = "NA";
120    return procMemInfo;
121}
122
123std::map<std::string, std::string> RAM::GetSysRamInfo() const
124{
125    std::map<std::string, std::string> sysRamInfo;
126    std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
127    if (collector == nullptr) {
128        LOGE("RAM::GetSysRamInfo collector is nullptr!");
129        return sysRamInfo;
130    }
131    CollectResult<SysMemory> result = collector->CollectSysMemory();
132    sysRamInfo["memTotal"] = std::to_string(result.data.memTotal);
133    sysRamInfo["memFree"] = std::to_string(result.data.memFree);
134    sysRamInfo["memAvailable"] = std::to_string(result.data.memAvailable);
135    return sysRamInfo;
136}
137
138void RAM::SetPackageName(const std::string &pName)
139{
140    packageName = pName;
141}
142
143void RAM::SetProcessId(const std::string &pid)
144{
145    processId = pid;
146}
147
148std::map<std::string, std::string> RAM::GetRamInfo() const
149{
150    std::map<std::string, std::string> procRamInfo;
151    std::string pssValue = "";
152    std::string cmd = HIDUMPER_CMD_MAP.at(HidumperCmd::DUMPER_MEM) + processId;
153    FILE *fd = popen(cmd.c_str(), "r");
154    if (fd == nullptr) {
155        return procRamInfo;
156    }
157    std::vector<std::string> paramsInfo;
158    procRamInfo = GetPssRamInfo(fd, paramsInfo);
159    for (const auto& value : paramsInfo) {
160        if (procRamInfo[value].empty()) {
161            procRamInfo[value] = "0";
162        }
163    }
164    return procRamInfo;
165}
166
167std::map<std::string, std::string> RAM::GetPssRamInfo(FILE *fd, std::vector<std::string> paramsInfo) const
168{
169    std::map<std::string, std::string> pssRamInfo = ParsePssValues(fd, paramsInfo);
170    std::map<std::string, std::string> sumRamInfo = SaveSumRamInfo(paramsInfo);
171    pssRamInfo.insert(sumRamInfo.cbegin(), sumRamInfo.cend());
172    if (paramsInfo.empty()) {
173        for (auto &pss : pssRamInfo) {
174            pss.second = "0";
175        }
176        return pssRamInfo;
177    }
178    return pssRamInfo;
179}
180
181std::map<std::string, std::string> RAM::ParsePssValues(FILE *fd, std::vector<std::string> &paramsInfo) const
182{
183    std::map<std::string, std::string> pssRamInfo;
184    std::string gpuPssValue = "0";
185    std::string graphicPssValue = "0";
186    std::string arktsHeapPssValue = "0";
187    std::string nativeHeapPssValue = "0";
188    std::string stackPssValue = "0";
189    const int paramEleven = 11;
190    char buf[1024] = {'\0'};
191    while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
192        std::string line = buf;
193        if (line[0] == '-') {
194            continue;
195        }
196        std::vector<std::string> params;
197        SPUtils::StrSplit(line, " ", params);
198        if (params.size() == paramEleven && params[0].find("GL") != std::string::npos) {
199            gpuPssValue = params[1];
200        }
201        if (params.size() == paramEleven && params[0].find("Graph") != std::string::npos) {
202            graphicPssValue = params[1];
203        }
204        if (params[0].find("ark") != std::string::npos) {
205            arktsHeapPssValue = params[RAM_THIRD];
206        }
207        if (params[0].find("native") != std::string::npos && params[1].find("heap") != std::string::npos) {
208            nativeHeapPssValue = params[RAM_SECOND];
209        }
210        if (params.size() == paramEleven && params[0].find("stack") != std::string::npos) {
211            stackPssValue = params[1];
212        }
213        if (params.size() == paramEleven && params[0].find("Total") != std::string::npos) {
214            paramsInfo = params;
215        }
216        if (paramsInfo.size() > 0) {
217            break;
218        }
219    }
220    pclose(fd);
221    pssRamInfo["gpuPss"] = gpuPssValue;
222    pssRamInfo["graphicPss"] = graphicPssValue;
223    pssRamInfo["arktsHeapPss"] = arktsHeapPssValue;
224    pssRamInfo["nativeHeapPss"] = nativeHeapPssValue;
225    pssRamInfo["stackPss"] = stackPssValue;
226    return pssRamInfo;
227}
228
229std::map<std::string, std::string> RAM::SaveSumRamInfo(std::vector<std::string> paramsInfo) const
230{
231    std::map<std::string, std::string> sumRamInfo;
232    if (paramsInfo.empty()) {
233        sumRamInfo = ProcMemNaInfo();
234        for (auto &sumRam : sumRamInfo) {
235            sumRam.second = "0";
236        }
237        return sumRamInfo;
238    }
239    sumRamInfo["pss"] = paramsInfo[RAM_ONE];
240    sumRamInfo["sharedClean"] = paramsInfo[RAM_SECOND];
241    sumRamInfo["sharedDirty"] = paramsInfo[RAM_THIRD];
242    sumRamInfo["privateClean"] = paramsInfo[RAM_FOURTH];
243    sumRamInfo["privateDirty"] = paramsInfo[RAM_FIFTH];
244    sumRamInfo["swap"] = paramsInfo[RAM_SIXTH];
245    sumRamInfo["swapPss"] = paramsInfo[RAM_SEVENTH];
246    sumRamInfo["heapSize"] = paramsInfo[RAM_EIGHTH];
247    sumRamInfo["heapAlloc"] = paramsInfo[RAM_NINTH];
248    sumRamInfo["heapFree"] = paramsInfo[RAM_TENTH].erase(static_cast<int>(paramsInfo[RAM_TENTH].size()) - 1);
249    return sumRamInfo;
250}
251}
252}
253