Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "qs_proc_mem_statistic.h"
12 :
13 : #include <string>
14 : #include <fstream>
15 : #include <securec.h>
16 : #include "bqs_util.h"
17 :
18 : namespace bqs {
19 : namespace {
20 : constexpr const char* VM_RSS_NAME = "VmRSS:";
21 : constexpr const char* VM_HWM_NAME = "VmHWM:";
22 : constexpr const char* XSMEME_NAME = "summary:";
23 : const std::string SVM_STAT_NAME = "peak_page_cnt=";
24 : constexpr const uint64_t DEFAULT_PAGE_SIZE = 4 * 1024UL;
25 : constexpr const uint64_t H_PAGE_SIZE = 2 * 1024 * 1024UL;
26 : constexpr const uint64_t BYTE_TO_KBYTE = 1024UL;
27 : constexpr const int32_t SVM_VALUE_CNT = 2;
28 : constexpr const int32_t XSMEM_VALUE_CNT = 2;
29 : } // namespace
30 13 : QsProcMemStatistic::QsProcMemStatistic() : runDevice_(false), curPid_(0) {}
31 :
32 13 : QsProcMemStatistic::~QsProcMemStatistic() {}
33 :
34 4 : bool QsProcMemStatistic::GetSvmInfoFromFile(uint64_t& svmValue)
35 : {
36 4 : std::ifstream svmFile(svmMemCfgFile_);
37 4 : if (!svmFile) {
38 1 : BQS_LOG_INFO(
39 : "open svmMem file not success, pid=%d, errno=%d, strerror=%s", static_cast<int32_t>(curPid_), errno,
40 : strerror(errno));
41 1 : return false;
42 : }
43 6 : const ScopeGuard fileGuard([&svmFile]() { svmFile.close(); });
44 3 : std::string svmStrInfo;
45 3 : std::string curLine;
46 4 : while (getline(svmFile, curLine)) {
47 3 : const size_t pos = curLine.find(SVM_STAT_NAME);
48 3 : if (pos != std::string::npos) {
49 2 : svmStrInfo = curLine.substr(pos);
50 2 : break;
51 : }
52 : }
53 :
54 3 : if (svmStrInfo.empty()) {
55 1 : BQS_LOG_WARN("svmStrInfo is empty");
56 1 : return false;
57 : }
58 :
59 2 : uint64_t normalPkgCnt = 0;
60 2 : uint64_t hugePkgCnt = 0;
61 : const int32_t ret =
62 2 : sscanf_s(svmStrInfo.c_str(), "peak_page_cnt=%llu; peak_hpage_cnt=%llu", &normalPkgCnt, &hugePkgCnt);
63 2 : if (ret < SVM_VALUE_CNT) {
64 1 : BQS_LOG_WARN(
65 : "get svmStrInfo:%s failed, ret:%d, peakHPgCnt:%lu, peakHPgCnt:%lu", svmStrInfo.c_str(), ret, normalPkgCnt,
66 : hugePkgCnt);
67 1 : return false;
68 : }
69 :
70 1 : BQS_LOG_INFO("peakPgCnt:%lu, peakHPgCnt:%lu summary:%s.", normalPkgCnt, hugePkgCnt, svmStrInfo.c_str());
71 1 : if ((normalPkgCnt == 0UL) && (hugePkgCnt == 0UL)) {
72 0 : return false;
73 : }
74 1 : svmValue = normalPkgCnt * DEFAULT_PAGE_SIZE + hugePkgCnt * H_PAGE_SIZE;
75 1 : return true;
76 4 : }
77 :
78 5 : void QsProcMemStatistic::StatisticProcSvmMemInfo()
79 : {
80 5 : if (!runDevice_) {
81 4 : return;
82 : }
83 4 : uint64_t svmValue = 0UL;
84 4 : if (!GetSvmInfoFromFile(svmValue)) {
85 3 : return;
86 : }
87 1 : if (svmValue > svmMem_.memHwm) {
88 1 : svmMem_.memHwm = svmValue;
89 : }
90 1 : svmMem_.memTotal += svmValue;
91 1 : svmMem_.statCnt++;
92 : }
93 :
94 4 : bool QsProcMemStatistic::GetXsMemInfoFromFile(uint64_t& xsMemValue)
95 : {
96 4 : std::ifstream inFile(xsMemCfgFile_);
97 4 : if (!inFile) {
98 1 : BQS_LOG_INFO(
99 : "open xsMem file not success, pid=%d, errno=%d, strerror=%s", static_cast<int32_t>(curPid_), errno,
100 : strerror(errno));
101 1 : return false;
102 : }
103 6 : const ScopeGuard fileGuard([&inFile]() { inFile.close(); });
104 3 : std::string summaryStr;
105 3 : std::string inputLine;
106 4 : while (getline(inFile, inputLine)) {
107 3 : if (inputLine.compare(0, strlen(XSMEME_NAME), XSMEME_NAME) == 0) {
108 2 : summaryStr = std::move(inputLine);
109 2 : break;
110 : }
111 : }
112 :
113 3 : if (summaryStr.empty()) {
114 1 : BQS_LOG_WARN("summaryStr is empty");
115 1 : return false;
116 : }
117 :
118 2 : uint64_t allocSize = 0;
119 2 : uint64_t realSize = 0;
120 2 : const int32_t ret = sscanf_s(summaryStr.c_str(), "summary: %llu %llu", &allocSize, &realSize);
121 2 : if (ret < XSMEM_VALUE_CNT) {
122 1 : BQS_LOG_WARN(
123 : "read summaryStr:%s failed, ret:%d, allocsize:%lu, real size:%lu", summaryStr.c_str(), ret, allocSize,
124 : realSize);
125 1 : return false;
126 : }
127 :
128 1 : BQS_LOG_INFO("allocsize:%lu B, real size:%lu B, %s.", allocSize, realSize, summaryStr.c_str());
129 1 : if (realSize == 0) {
130 0 : return false;
131 : }
132 1 : xsMemValue = realSize;
133 1 : return true;
134 4 : }
135 :
136 4 : void QsProcMemStatistic::StatisticProcXsMemInfo()
137 : {
138 4 : uint64_t xsMemValue = 0UL;
139 4 : if (!GetXsMemInfoFromFile(xsMemValue)) {
140 3 : return;
141 : }
142 1 : if (xsMemValue > xsMem_.memHwm) {
143 1 : xsMem_.memHwm = xsMemValue;
144 : }
145 1 : xsMem_.memTotal += xsMemValue;
146 1 : xsMem_.statCnt++;
147 : }
148 :
149 4 : bool QsProcMemStatistic::GetOsMemInfoFromFile(uint64_t& rssValue, uint64_t& hwmValue)
150 : {
151 4 : std::ifstream ifFile(rssMemCfgFile_);
152 4 : if (!ifFile) {
153 1 : BQS_LOG_INFO(
154 : "open rss file not success, pid=%d, errno=%d, strerror=%s", static_cast<int32_t>(curPid_), errno,
155 : strerror(errno));
156 1 : return false;
157 : }
158 6 : const ScopeGuard fileGuard([&ifFile]() { ifFile.close(); });
159 3 : std::string vmRssStr;
160 3 : std::string vmHwmStr;
161 3 : std::string inputLine;
162 26 : while (getline(ifFile, inputLine)) {
163 25 : if (inputLine.compare(0, strlen(VM_RSS_NAME), VM_RSS_NAME) == 0) {
164 2 : vmRssStr = std::move(inputLine);
165 23 : } else if (inputLine.compare(0, strlen(VM_HWM_NAME), VM_HWM_NAME) == 0) {
166 2 : vmHwmStr = std::move(inputLine);
167 : } else {
168 21 : continue;
169 : }
170 4 : if ((!vmRssStr.empty()) && (!vmHwmStr.empty())) {
171 2 : break;
172 : }
173 : }
174 :
175 3 : if ((vmRssStr.empty()) || (vmHwmStr.empty())) {
176 1 : BQS_LOG_RUN_INFO("cannot get vmrss or vmhwm");
177 1 : return false;
178 : }
179 :
180 2 : if (!bqs::TransStrToull(vmRssStr.substr(strlen(VM_RSS_NAME)), rssValue)) {
181 1 : BQS_LOG_INFO("get vmRssError:%s nok", vmRssStr.c_str());
182 1 : return false;
183 : }
184 :
185 1 : if (!bqs::TransStrToull(vmHwmStr.substr(strlen(VM_HWM_NAME)), hwmValue)) {
186 0 : BQS_LOG_INFO("get vmHwmError:%s nok", vmRssStr.c_str());
187 0 : return false;
188 : }
189 1 : BQS_LOG_INFO("vmRss:%lu KB, vmHwm:%lu KB.", rssValue, hwmValue);
190 1 : return true;
191 4 : }
192 :
193 3 : void QsProcMemStatistic::StatisticProcOsMemInfo()
194 : {
195 3 : uint64_t rssValue = 0UL;
196 3 : uint64_t hwmValue = 0UL;
197 3 : if (!GetOsMemInfoFromFile(rssValue, hwmValue)) {
198 2 : BQS_LOG_INFO("get os meminfo nok");
199 2 : return;
200 : }
201 1 : rssMem_.memHwm = hwmValue;
202 1 : rssMem_.memTotal += rssValue;
203 1 : rssMem_.statCnt++;
204 : }
205 :
206 1 : void QsProcMemStatistic::StatisticProcMemInfo()
207 : {
208 1 : StatisticProcOsMemInfo();
209 1 : StatisticProcXsMemInfo();
210 1 : StatisticProcSvmMemInfo();
211 1 : }
212 :
213 18 : bool QsProcMemStatistic::InitProcMemStatistic()
214 : {
215 18 : runDevice_ = (bqs::GetRunContext() == bqs::RunContext::DEVICE);
216 18 : auto ret = memset_s(&rssMem_, sizeof(rssMem_), 0x00, sizeof(rssMem_));
217 18 : if (ret != EOK) {
218 0 : BQS_LOG_ERROR("memset rssMem failed ret:%d", ret);
219 0 : return false;
220 : }
221 :
222 18 : ret = memset_s(&svmMem_, sizeof(svmMem_), 0x00, sizeof(svmMem_));
223 18 : if (ret != EOK) {
224 0 : BQS_LOG_ERROR("memset svmMem_ failed ret:%d", ret);
225 0 : return false;
226 : }
227 :
228 18 : ret = memset_s(&xsMem_, sizeof(xsMem_), 0x00, sizeof(xsMem_));
229 18 : if (ret != EOK) {
230 0 : BQS_LOG_ERROR("memset xsMem_ failed ret:%d", ret);
231 0 : return false;
232 : }
233 18 : curPid_ = getpid();
234 18 : if (curPid_ < 0) {
235 0 : BQS_LOG_ERROR("get pid error:%d", curPid_);
236 0 : return false;
237 : }
238 18 : rssMemCfgFile_ = "/proc/" + std::to_string(curPid_) + "/status";
239 18 : xsMemCfgFile_ = "/proc/xsmem/task/" + std::to_string(curPid_) + "/summary";
240 18 : svmMemCfgFile_ = "/proc/svm/task/" + std::to_string(curPid_) + "/summary";
241 18 : return true;
242 : }
243 :
244 311 : void QsProcMemStatistic::PrintOutProcMemInfo(const uint32_t hostPid)
245 : {
246 311 : uint64_t rssavg = 0UL;
247 311 : if (rssMem_.statCnt > 0) {
248 4 : rssavg = rssMem_.memTotal / rssMem_.statCnt;
249 : }
250 311 : BQS_LOG_INFO("rssavg:%lu KB, rsstotal:%lu KB, rsscnt:%lu", rssavg, rssMem_.memTotal, rssMem_.statCnt);
251 311 : uint64_t xsmAvg = 0UL;
252 311 : if (xsMem_.statCnt > 0) {
253 1 : xsmAvg = xsMem_.memTotal / xsMem_.statCnt;
254 : }
255 311 : BQS_LOG_INFO("xsmAvg:%lu B, xsmtotal:%lu B, xsmcnt:%lu", xsmAvg, xsMem_.memTotal, xsMem_.statCnt);
256 311 : if (runDevice_) {
257 31 : uint64_t svmAvg = 0UL;
258 31 : if (svmMem_.statCnt > 0) {
259 1 : svmAvg = svmMem_.memTotal / svmMem_.statCnt;
260 : }
261 31 : BQS_LOG_INFO("svmAvg:%lu B, svmtotal:%lu B, svmcnt:%lu", svmAvg, svmMem_.memTotal, svmMem_.statCnt);
262 31 : BQS_LOG_RUN_INFO(
263 : "proc_metrics:pid=%u, rssavg=%lu B, rsshwm=%lu B, xsmemavg=%lu B, xsmemhwm=%lu B, "
264 : "svmmemavg=%lu B, svmmemhwm=%lu B",
265 : hostPid, rssavg * BYTE_TO_KBYTE, rssMem_.memHwm * BYTE_TO_KBYTE, xsmAvg, xsMem_.memHwm, svmAvg,
266 : svmMem_.memHwm);
267 : } else {
268 280 : BQS_LOG_RUN_INFO(
269 : "proc_metrics:pid=%u, rssavg=%lu B, rsshwm=%lu B, xsmemavg=%lu B, xsmemhwm=%lu B", hostPid,
270 : rssavg * BYTE_TO_KBYTE, rssMem_.memHwm * BYTE_TO_KBYTE, xsmAvg, xsMem_.memHwm);
271 : }
272 311 : }
273 : } // namespace bqs
|