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 "aicpusd_proc_mem_statistic.h"
12 :
13 : #include <string>
14 : #include <fstream>
15 : #include "aicpusd_util.h"
16 :
17 : namespace AicpuSchedule {
18 : namespace {
19 : constexpr const char* VM_RSS_NAME = "VmRSS:";
20 : constexpr const char* VM_HWM_NAME = "VmHWM:";
21 : constexpr const char* XSMEME_NAME = "summary:";
22 : const std::string SVM_STAT_NAME = "peak_page_cnt=";
23 : constexpr const uint64_t DEFAULT_PAGE_SIZE = 4 * 1024UL;
24 : constexpr const uint64_t H_PAGE_SIZE = 2 * 1024 * 1024UL;
25 : constexpr const uint64_t BYTE_TO_KBYTE = 1024UL;
26 : constexpr const int32_t SVM_VALUE_CNT = 2;
27 : constexpr const int32_t XSMEM_VALUE_CNT = 2;
28 : } // namespace
29 12 : AicpuSdProcMemStatistic::AicpuSdProcMemStatistic() : deployCtx_(DeployContext::HOST), curPid_(0) {}
30 :
31 12 : AicpuSdProcMemStatistic::~AicpuSdProcMemStatistic() {}
32 :
33 5 : void AicpuSdProcMemStatistic::StatisticProcSvmMemInfo()
34 : {
35 5 : if (deployCtx_ != DeployContext::DEVICE) {
36 4 : return;
37 : }
38 4 : uint64_t svmValue = 0UL;
39 4 : if (!GetSvmInfoFromFile(svmValue)) {
40 3 : return;
41 : }
42 1 : if (svmValue > svmMem_.memHwm) {
43 1 : svmMem_.memHwm = svmValue;
44 : }
45 1 : svmMem_.memTotal += svmValue;
46 1 : svmMem_.statCnt++;
47 : }
48 :
49 4 : bool AicpuSdProcMemStatistic::GetSvmInfoFromFile(uint64_t& svmValue)
50 : {
51 4 : std::ifstream inFile(svmMemCfgFile_);
52 4 : if (!inFile) {
53 1 : aicpusd_info(
54 : "Opening svmMem file was not successful, pid=%d, errno=%d, reason:%s", static_cast<int32_t>(curPid_), errno,
55 : strerror(errno));
56 1 : return false;
57 : }
58 6 : const ScopeGuard fileGuard([&inFile]() { inFile.close(); });
59 3 : std::string summaryStr;
60 3 : std::string inputLine;
61 4 : while (getline(inFile, inputLine)) {
62 3 : const size_t pos = inputLine.find(SVM_STAT_NAME);
63 3 : if (pos != std::string::npos) {
64 2 : summaryStr = inputLine.substr(pos);
65 2 : break;
66 : }
67 : }
68 :
69 3 : if (summaryStr.empty()) {
70 1 : aicpusd_warn("summaryStr is empty");
71 1 : return false;
72 : }
73 :
74 2 : uint64_t peakPgCnt = 0;
75 2 : uint64_t peakHPgCnt = 0;
76 : const int32_t ret =
77 2 : sscanf_s(summaryStr.c_str(), "peak_page_cnt=%llu; peak_hpage_cnt=%llu", &peakPgCnt, &peakHPgCnt);
78 2 : if (ret < SVM_VALUE_CNT) {
79 1 : aicpusd_warn(
80 : "read summaryStr:%s failed, ret:%d, peakHPgCnt:%llu, peakHPgCnt:%llu", summaryStr.c_str(), ret, peakPgCnt,
81 : peakHPgCnt);
82 1 : return false;
83 : }
84 :
85 1 : aicpusd_info("peakPgCnt:%lu, peakHPgCnt:%lu summary:%s.", peakPgCnt, peakHPgCnt, summaryStr.c_str());
86 1 : if ((peakPgCnt == 0) && (peakHPgCnt == 0UL)) {
87 0 : return false;
88 : }
89 1 : svmValue = peakPgCnt * DEFAULT_PAGE_SIZE + peakHPgCnt + H_PAGE_SIZE;
90 1 : return true;
91 4 : }
92 :
93 4 : bool AicpuSdProcMemStatistic::GetXsMemInfoFromFile(uint64_t& xsMemValue)
94 : {
95 4 : std::ifstream inFile(xsMemCfgFile_);
96 4 : if (!inFile) {
97 1 : aicpusd_info(
98 : "Opening xsMem file was not successful, pid=%d, errno=%d, reason:%s", static_cast<int32_t>(curPid_), errno,
99 : strerror(errno));
100 1 : return false;
101 : }
102 6 : const ScopeGuard fileGuard([&inFile]() { inFile.close(); });
103 3 : std::string summaryStr;
104 3 : std::string inputLine;
105 4 : while (getline(inFile, inputLine)) {
106 3 : if (inputLine.compare(0, strlen(XSMEME_NAME), XSMEME_NAME) == 0) {
107 2 : summaryStr = std::move(inputLine);
108 2 : break;
109 : }
110 : }
111 :
112 3 : if (summaryStr.empty()) {
113 1 : aicpusd_warn("summaryStr is empty");
114 1 : return false;
115 : }
116 :
117 2 : uint64_t allocSize = 0;
118 2 : uint64_t realSize = 0;
119 2 : const int32_t ret = sscanf_s(summaryStr.c_str(), "summary: %llu %llu", &allocSize, &realSize);
120 2 : if (ret < XSMEM_VALUE_CNT) {
121 1 : aicpusd_warn(
122 : "read summaryStr:%s failed, ret:%d, allocsize:%llu, real size:%llu", summaryStr.c_str(), ret, allocSize,
123 : realSize);
124 1 : return false;
125 : }
126 :
127 1 : aicpusd_info("allocsize:%lu B, real size:%lu B, %s.", allocSize, realSize, summaryStr.c_str());
128 1 : if (realSize == 0) {
129 0 : return false;
130 : }
131 1 : xsMemValue = realSize;
132 1 : return true;
133 4 : }
134 :
135 4 : void AicpuSdProcMemStatistic::StatisticProcXsMemInfo()
136 : {
137 4 : uint64_t xsMemValue = 0UL;
138 4 : if (!GetXsMemInfoFromFile(xsMemValue)) {
139 3 : return;
140 : }
141 1 : if (xsMemValue > xsMem_.memHwm) {
142 1 : xsMem_.memHwm = xsMemValue;
143 : }
144 1 : xsMem_.memTotal += xsMemValue;
145 1 : xsMem_.statCnt++;
146 : }
147 :
148 4 : bool AicpuSdProcMemStatistic::GetOsMemInfoFromFile(uint64_t& rssValue, uint64_t& hwmValue)
149 : {
150 4 : std::ifstream ifFile(rssMemCfgFile_);
151 4 : if (!ifFile) {
152 1 : aicpusd_info(
153 : "Opening rss file was not successful, pid=%d, errno=%d, reason:%s", static_cast<int32_t>(curPid_), errno,
154 : 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 : aicpusd_run_info("cannot get vmrss or vmhwm");
176 1 : return false;
177 : }
178 :
179 2 : if (!AicpuUtil::TransStrToull(vmRssStr.substr(strlen(VM_RSS_NAME)), rssValue)) {
180 1 : aicpusd_warn("get vmRssError:%s failed", vmRssStr.c_str());
181 1 : return false;
182 : }
183 :
184 1 : if (!AicpuUtil::TransStrToull(vmHwmStr.substr(strlen(VM_HWM_NAME)), hwmValue)) {
185 0 : aicpusd_warn("get vmHwmError:%s failed", vmHwmStr.c_str());
186 0 : return false;
187 : }
188 1 : aicpusd_info("vmRss:%llu KB, vmHwm:%llu KB.", rssValue, hwmValue);
189 1 : return true;
190 4 : }
191 :
192 3 : void AicpuSdProcMemStatistic::StatisticProcOsMemInfo()
193 : {
194 3 : uint64_t rssValue = 0UL;
195 3 : uint64_t hwmValue = 0UL;
196 3 : if (!GetOsMemInfoFromFile(rssValue, hwmValue)) {
197 2 : aicpusd_warn("get os meminfo failed");
198 2 : return;
199 : }
200 1 : rssMem_.memHwm = hwmValue;
201 1 : rssMem_.memTotal += rssValue;
202 1 : rssMem_.statCnt++;
203 : }
204 :
205 1 : void AicpuSdProcMemStatistic::StatisticProcMemInfo()
206 : {
207 1 : StatisticProcOsMemInfo();
208 1 : StatisticProcXsMemInfo();
209 1 : StatisticProcSvmMemInfo();
210 1 : }
211 :
212 1 : bool AicpuSdProcMemStatistic::InitProcMemStatistic()
213 : {
214 1 : auto ret = memset_s(&rssMem_, sizeof(rssMem_), 0x00, sizeof(rssMem_));
215 1 : if (ret != EOK) {
216 0 : aicpusd_err("memset rssMem failed ret:%d", ret);
217 0 : return false;
218 : }
219 :
220 1 : ret = memset_s(&svmMem_, sizeof(svmMem_), 0x00, sizeof(svmMem_));
221 1 : if (ret != EOK) {
222 0 : aicpusd_err("memset svmMem_ failed ret:%d", ret);
223 0 : return false;
224 : }
225 :
226 1 : ret = memset_s(&xsMem_, sizeof(xsMem_), 0x00, sizeof(xsMem_));
227 1 : if (ret != EOK) {
228 0 : aicpusd_err("memset xsMem_ failed ret:%d", ret);
229 0 : return false;
230 : }
231 1 : (void)GetAicpuDeployContext(deployCtx_);
232 1 : curPid_ = getpid();
233 1 : if (curPid_ < 0) {
234 0 : aicpusd_err("get pid error:%d", curPid_);
235 0 : return false;
236 : }
237 1 : rssMemCfgFile_ = "/proc/" + std::to_string(curPid_) + "/status";
238 1 : xsMemCfgFile_ = "/proc/xsmem/task/" + std::to_string(curPid_) + "/summary";
239 1 : svmMemCfgFile_ = "/proc/svm/task/" + std::to_string(curPid_) + "/summary";
240 1 : return true;
241 : }
242 :
243 5 : void AicpuSdProcMemStatistic::PrintOutProcMemInfo(const uint32_t hostPid)
244 : {
245 5 : uint64_t rssavg = 0UL;
246 5 : if (rssMem_.statCnt > 0) {
247 2 : rssavg = rssMem_.memTotal / rssMem_.statCnt;
248 : }
249 5 : aicpusd_info("rssavg:%llu KB, rsstotal:%llu KB, rsscnt:%llu", rssavg, rssMem_.memTotal, rssMem_.statCnt);
250 5 : uint64_t xsmAvg = 0UL;
251 5 : if (xsMem_.statCnt > 0) {
252 1 : xsmAvg = xsMem_.memTotal / xsMem_.statCnt;
253 : }
254 5 : aicpusd_info("xsmAvg:%llu B, xsmtotal:%llu B, xsmcnt:%llu", xsmAvg, xsMem_.memTotal, xsMem_.statCnt);
255 5 : if (deployCtx_ == DeployContext::DEVICE) {
256 3 : uint64_t svmAvg = 0UL;
257 3 : if (svmMem_.statCnt > 0) {
258 1 : svmAvg = svmMem_.memTotal / svmMem_.statCnt;
259 : }
260 3 : aicpusd_info("svmAvg:%llu B, svmtotal:%llu B, svmcnt:%llu", svmAvg, svmMem_.memTotal, svmMem_.statCnt);
261 3 : aicpusd_run_info(
262 : "proc_metrics:pid=%u, rssavg=%lu B, rsshwm=%llu B, xsmemavg=%llu B, xsmemhwm=%lu B, "
263 : "svmmemavg=%llu B, svmmemhwm=%lu B",
264 : hostPid, rssavg * BYTE_TO_KBYTE, rssMem_.memHwm * BYTE_TO_KBYTE, xsmAvg, xsMem_.memHwm, svmAvg,
265 : svmMem_.memHwm);
266 : } else {
267 2 : aicpusd_run_info(
268 : "proc_metrics:pid=%u, rssavg=%lu B, rsshwm=%llu B, xsmemavg=%llu B, xsmemhwm=%lu B", hostPid,
269 : rssavg * BYTE_TO_KBYTE, rssMem_.memHwm * BYTE_TO_KBYTE, xsmAvg, xsMem_.memHwm);
270 : }
271 5 : }
272 : } // namespace AicpuSchedule
|