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 : }
30 13 : QsProcMemStatistic::QsProcMemStatistic() : runDevice_(false), curPid_(0)
31 : {
32 13 : }
33 :
34 13 : QsProcMemStatistic::~QsProcMemStatistic()
35 : {
36 13 : }
37 :
38 4 : bool QsProcMemStatistic::GetSvmInfoFromFile(uint64_t &svmValue)
39 : {
40 4 : std::ifstream svmFile(svmMemCfgFile_);
41 4 : if (!svmFile) {
42 1 : BQS_LOG_INFO("open svmMem file not success, pid=%d, errno=%d, strerror=%s", static_cast<int32_t>(curPid_),
43 : errno, strerror(errno));
44 1 : return false;
45 : }
46 6 : const ScopeGuard fileGuard([&svmFile] () { svmFile.close(); });
47 3 : std::string svmStrInfo;
48 3 : std::string curLine;
49 4 : while (getline(svmFile, curLine)) {
50 3 : const size_t pos = curLine.find(SVM_STAT_NAME);
51 3 : if (pos != std::string::npos) {
52 2 : svmStrInfo = curLine.substr(pos);
53 2 : break;
54 : }
55 : }
56 :
57 3 : if (svmStrInfo.empty()) {
58 1 : BQS_LOG_WARN("svmStrInfo is empty");
59 1 : return false;
60 : }
61 :
62 2 : uint64_t normalPkgCnt = 0;
63 2 : uint64_t hugePkgCnt = 0;
64 2 : const int32_t ret = sscanf_s(svmStrInfo.c_str(), "peak_page_cnt=%llu; peak_hpage_cnt=%llu",
65 : &normalPkgCnt, &hugePkgCnt);
66 2 : if (ret < SVM_VALUE_CNT) {
67 1 : BQS_LOG_WARN("get svmStrInfo:%s failed, ret:%d, peakHPgCnt:%lu, peakHPgCnt:%lu", svmStrInfo.c_str(),
68 : ret, normalPkgCnt, hugePkgCnt);
69 1 : return false;
70 : }
71 :
72 1 : BQS_LOG_INFO("peakPgCnt:%lu, peakHPgCnt:%lu summary:%s.", normalPkgCnt, hugePkgCnt, svmStrInfo.c_str());
73 1 : if ((normalPkgCnt == 0UL) && (hugePkgCnt == 0UL)) {
74 0 : return false;
75 : }
76 1 : svmValue = normalPkgCnt * DEFAULT_PAGE_SIZE + hugePkgCnt * H_PAGE_SIZE;
77 1 : return true;
78 4 : }
79 :
80 5 : void QsProcMemStatistic::StatisticProcSvmMemInfo()
81 : {
82 5 : if (!runDevice_) {
83 4 : return;
84 : }
85 4 : uint64_t svmValue = 0UL;
86 4 : if (!GetSvmInfoFromFile(svmValue)) {
87 3 : return;
88 : }
89 1 : if (svmValue > svmMem_.memHwm) {
90 1 : svmMem_.memHwm = svmValue;
91 : }
92 1 : svmMem_.memTotal += svmValue;
93 1 : svmMem_.statCnt++;
94 : }
95 :
96 4 : bool QsProcMemStatistic::GetXsMemInfoFromFile(uint64_t &xsMemValue)
97 : {
98 4 : std::ifstream inFile(xsMemCfgFile_);
99 4 : if (!inFile) {
100 1 : BQS_LOG_INFO("open xsMem file not success, pid=%d, errno=%d, strerror=%s", static_cast<int32_t>(curPid_),
101 : errno, strerror(errno));
102 1 : return false;
103 : }
104 6 : const ScopeGuard fileGuard([&inFile] () { inFile.close(); });
105 3 : std::string summaryStr;
106 3 : std::string inputLine;
107 4 : while (getline(inFile, inputLine)) {
108 3 : if (inputLine.compare(0, strlen(XSMEME_NAME), XSMEME_NAME) == 0) {
109 2 : summaryStr = std::move(inputLine);
110 2 : break;
111 : }
112 : }
113 :
114 3 : if (summaryStr.empty()) {
115 1 : BQS_LOG_WARN("summaryStr is empty");
116 1 : return false;
117 : }
118 :
119 2 : uint64_t allocSize = 0;
120 2 : uint64_t realSize = 0;
121 2 : const int32_t ret = sscanf_s(summaryStr.c_str(), "summary: %llu %llu", &allocSize, &realSize);
122 2 : if (ret < XSMEM_VALUE_CNT) {
123 1 : BQS_LOG_WARN("read summaryStr:%s failed, ret:%d, allocsize:%lu, real size:%lu", summaryStr.c_str(), ret,
124 : allocSize, 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("open rss file not success, pid=%d, errno=%d, strerror=%s", static_cast<int32_t>(curPid_),
154 : errno, strerror(errno));
155 1 : return false;
156 : }
157 6 : const ScopeGuard fileGuard([&ifFile] () { ifFile.close(); });
158 3 : std::string vmRssStr;
159 3 : std::string vmHwmStr;
160 3 : std::string inputLine;
161 26 : while (getline(ifFile, inputLine)) {
162 25 : if (inputLine.compare(0, strlen(VM_RSS_NAME), VM_RSS_NAME) == 0) {
163 2 : vmRssStr = std::move(inputLine);
164 23 : } else if (inputLine.compare(0, strlen(VM_HWM_NAME), VM_HWM_NAME) == 0) {
165 2 : vmHwmStr = std::move(inputLine);
166 : } else {
167 21 : continue;
168 : }
169 4 : if ((!vmRssStr.empty()) && (!vmHwmStr.empty())) {
170 2 : break;
171 : }
172 : }
173 :
174 3 : if ((vmRssStr.empty()) || (vmHwmStr.empty())) {
175 1 : BQS_LOG_RUN_INFO("cannot get vmrss or vmhwm");
176 1 : return false;
177 : }
178 :
179 2 : if (!bqs::TransStrToull(vmRssStr.substr(strlen(VM_RSS_NAME)), rssValue)) {
180 1 : BQS_LOG_INFO("get vmRssError:%s nok", vmRssStr.c_str());
181 1 : return false;
182 : }
183 :
184 1 : if (!bqs::TransStrToull(vmHwmStr.substr(strlen(VM_HWM_NAME)), hwmValue)) {
185 0 : BQS_LOG_INFO("get vmHwmError:%s nok", vmRssStr.c_str());
186 0 : return false;
187 : }
188 1 : BQS_LOG_INFO("vmRss:%lu KB, vmHwm:%lu KB.", rssValue, hwmValue);
189 1 : return true;
190 4 : }
191 :
192 3 : void QsProcMemStatistic::StatisticProcOsMemInfo()
193 : {
194 3 : uint64_t rssValue = 0UL;
195 3 : uint64_t hwmValue = 0UL;
196 3 : if (!GetOsMemInfoFromFile(rssValue, hwmValue)) {
197 2 : BQS_LOG_INFO("get os meminfo nok");
198 2 : return;
199 : }
200 1 : rssMem_.memHwm = hwmValue;
201 1 : rssMem_.memTotal += rssValue;
202 1 : rssMem_.statCnt++;
203 : }
204 :
205 1 : void QsProcMemStatistic::StatisticProcMemInfo()
206 : {
207 1 : StatisticProcOsMemInfo();
208 1 : StatisticProcXsMemInfo();
209 1 : StatisticProcSvmMemInfo();
210 1 : }
211 :
212 18 : bool QsProcMemStatistic::InitProcMemStatistic()
213 : {
214 18 : runDevice_ = (bqs::GetRunContext() == bqs::RunContext::DEVICE);
215 18 : auto ret = memset_s(&rssMem_, sizeof(rssMem_), 0x00, sizeof(rssMem_));
216 18 : if (ret != EOK) {
217 0 : BQS_LOG_ERROR("memset rssMem failed ret:%d", ret);
218 0 : return false;
219 : }
220 :
221 18 : ret = memset_s(&svmMem_, sizeof(svmMem_), 0x00, sizeof(svmMem_));
222 18 : if (ret != EOK) {
223 0 : BQS_LOG_ERROR("memset svmMem_ failed ret:%d", ret);
224 0 : return false;
225 : }
226 :
227 18 : ret = memset_s(&xsMem_, sizeof(xsMem_), 0x00, sizeof(xsMem_));
228 18 : if (ret != EOK) {
229 0 : BQS_LOG_ERROR("memset xsMem_ failed ret:%d", ret);
230 0 : return false;
231 : }
232 18 : curPid_ = getpid();
233 18 : if (curPid_ < 0) {
234 0 : BQS_LOG_ERROR("get pid error:%d", curPid_);
235 0 : return false;
236 : }
237 18 : rssMemCfgFile_ = "/proc/" + std::to_string(curPid_) + "/status";
238 18 : xsMemCfgFile_ = "/proc/xsmem/task/" + std::to_string(curPid_) + "/summary";
239 18 : svmMemCfgFile_ = "/proc/svm/task/" + std::to_string(curPid_) + "/summary";
240 18 : return true;
241 : }
242 :
243 311 : void QsProcMemStatistic::PrintOutProcMemInfo(const uint32_t hostPid)
244 : {
245 311 : uint64_t rssavg = 0UL;
246 311 : if (rssMem_.statCnt > 0) {
247 4 : rssavg = rssMem_.memTotal / rssMem_.statCnt;
248 : }
249 311 : BQS_LOG_INFO("rssavg:%lu KB, rsstotal:%lu KB, rsscnt:%lu", rssavg, rssMem_.memTotal, rssMem_.statCnt);
250 311 : uint64_t xsmAvg = 0UL;
251 311 : if (xsMem_.statCnt > 0) {
252 1 : xsmAvg = xsMem_.memTotal / xsMem_.statCnt;
253 : }
254 311 : BQS_LOG_INFO("xsmAvg:%lu B, xsmtotal:%lu B, xsmcnt:%lu", xsmAvg, xsMem_.memTotal, xsMem_.statCnt);
255 311 : if (runDevice_) {
256 31 : uint64_t svmAvg = 0UL;
257 31 : if (svmMem_.statCnt > 0) {
258 1 : svmAvg = svmMem_.memTotal / svmMem_.statCnt;
259 : }
260 31 : BQS_LOG_INFO("svmAvg:%lu B, svmtotal:%lu B, svmcnt:%lu", svmAvg, svmMem_.memTotal, svmMem_.statCnt);
261 31 : BQS_LOG_RUN_INFO("proc_metrics:pid=%u, rssavg=%lu B, rsshwm=%lu B, xsmemavg=%lu B, xsmemhwm=%lu B, "
262 : "svmmemavg=%lu B, svmmemhwm=%lu B", hostPid, rssavg * BYTE_TO_KBYTE,
263 : rssMem_.memHwm * BYTE_TO_KBYTE, xsmAvg, xsMem_.memHwm, svmAvg, svmMem_.memHwm);
264 : } else {
265 280 : BQS_LOG_RUN_INFO("proc_metrics:pid=%u, rssavg=%lu B, rsshwm=%lu B, xsmemavg=%lu B, xsmemhwm=%lu B",
266 : hostPid, rssavg * BYTE_TO_KBYTE, rssMem_.memHwm * BYTE_TO_KBYTE, xsmAvg, xsMem_.memHwm);
267 : }
268 311 : }
269 : }
|