1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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
16 #include "cpu_data_plugin.h"
17
18 #include <ctime>
19 #include <vector>
20 #include <sstream>
21
22 #include "common.h"
23 #include "cpu_plugin_result.pbencoder.h"
24 #include "buffer_splitter.h"
25
26 namespace {
27 using namespace OHOS::Developtools::Profiler;
28 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
29 constexpr int SYSTEM_STAT_COUNT = 9;
30 constexpr int STAT_COUNT = 17;
31 constexpr int STAT_START = 13;
32 constexpr int THREAD_NAME_POS = 1;
33 constexpr int THREAD_STATE_POS = 2;
34 constexpr int CPU_USER_HZ_L = 100;
35 constexpr int CPU_USER_HZ_H = 1000;
36 constexpr int CPU_HZ_H = 10;
37 const int PERCENT = 100;
38
39 const std::string FREQUENCY_PATH = "/sys/devices/system/cpu";
40 const std::string FREQUENCY_MIN_PATH = "/cpufreq/cpuinfo_min_freq";
41 const std::string FREQUENCY_MAX_PATH = "/cpufreq/cpuinfo_max_freq";
42 const std::string FREQUENCY_CUR_PATH = "/cpufreq/cpuinfo_cur_freq";
43 } // namespace
44
CpuDataPlugin()45 CpuDataPlugin::CpuDataPlugin()
46 {
47 buffer_ = nullptr;
48 path_ = "/proc/";
49 err_ = -1;
50 pid_ = -1;
51 prevProcessCpuTime_ = 0;
52 prevCpuTimeData_ = {};
53 maxFreqIndex_ = -1;
54 freqPath_ = FREQUENCY_PATH;
55 }
56
~CpuDataPlugin()57 CpuDataPlugin::~CpuDataPlugin()
58 {
59 PROFILER_LOG_INFO(LOG_CORE, "%s:~CpuDataPlugin!", __func__);
60 if (buffer_ != nullptr) {
61 free(buffer_);
62 buffer_ = nullptr;
63 }
64
65 tidVec_.clear();
66 prevThreadCpuTimeMap_.clear();
67 prevCoreSystemCpuTimeMap_.clear();
68 prevCoreSystemBootTimeMap_.clear();
69 maxFrequencyVec_.clear();
70 minFrequencyVec_.clear();
71 }
72
GetCmdArgs(const CpuConfig & protoConfig)73 std::string CpuDataPlugin::GetCmdArgs(const CpuConfig& protoConfig)
74 {
75 std::stringstream args;
76 args << "pid: " << COMMON::GetProcessNameByPid(protoConfig.pid());
77 args << " report_process_info: " << (protoConfig.report_process_info() ? "true" : "false");
78 return args.str();
79 }
80
Start(const uint8_t * configData,uint32_t configSize)81 int CpuDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
82 {
83 buffer_ = malloc(READ_BUFFER_SIZE);
84 CHECK_NOTNULL(buffer_, RET_FAIL, "%s:malloc buffer_ failed!", __func__);
85 if (memset_s(buffer_, READ_BUFFER_SIZE, 0, READ_BUFFER_SIZE) != EOK) {
86 PROFILER_LOG_ERROR(LOG_CORE, "%s:memset_s error!", __func__);
87 }
88 CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
89 "%s:parseFromArray failed!", __func__);
90 auto args = GetCmdArgs(protoConfig_);
91 if (protoConfig_.pid() > 0) {
92 pid_ = protoConfig_.pid();
93 } else if (protoConfig_.report_process_info()) {
94 PROFILER_LOG_INFO(LOG_CORE, "%s:need report process info", __func__);
95 } else {
96 int ret = COMMON::PluginWriteToHisysevent("CPU_PLUGIN", "sh", args, RET_FAIL, "failed");
97 PROFILER_LOG_ERROR(LOG_CORE, "%s:invalid pid, record hisysevent result. %d", __func__, ret);
98 return RET_FAIL;
99 }
100
101 int ret = COMMON::PluginWriteToHisysevent("cpu_plugin", "sh", args, RET_SUCC, "success");
102 PROFILER_LOG_INFO(LOG_CORE, "%s:start success! hisysevent report cpu_plugin result: %d", __func__, ret);
103 return RET_SUCC;
104 }
105
ReportOptimize(RandomWriteCtx * randomWrite)106 int CpuDataPlugin::ReportOptimize(RandomWriteCtx* randomWrite)
107 {
108 ProtoEncoder::CpuData dataProto(randomWrite);
109
110 ProtoEncoder::CpuUsageInfo* cpuUsageInfo = nullptr;
111 WriteCpuUsageInfo(dataProto, cpuUsageInfo);
112
113 if (pid_ > 0 && (!protoConfig_.skip_thread_cpu_info())) {
114 WriteThreadInfo(dataProto);
115 }
116 if (protoConfig_.report_process_info()) {
117 WriteProcnum(dataProto);
118 }
119
120 int msgSize = dataProto.Finish();
121 return msgSize;
122 }
123
Report(uint8_t * data,uint32_t dataSize)124 int CpuDataPlugin::Report(uint8_t* data, uint32_t dataSize)
125 {
126 CpuData dataProto;
127 uint32_t length;
128
129 CpuUsageInfo* cpuUsageInfo = nullptr;
130 WriteCpuUsageInfo(dataProto, cpuUsageInfo);
131
132 if (pid_ > 0 && (!protoConfig_.skip_thread_cpu_info())) {
133 WriteThreadInfo(dataProto);
134 }
135 if (protoConfig_.report_process_info()) {
136 WriteProcnum(dataProto);
137 }
138
139 length = dataProto.ByteSizeLong();
140 if (length > dataSize) {
141 return -length;
142 }
143 if (dataProto.SerializeToArray(data, length) > 0) {
144 return length;
145 }
146 return 0;
147 }
148
WriteProcnum(T & cpuData)149 template <typename T> bool CpuDataPlugin::WriteProcnum(T& cpuData)
150 {
151 DIR* procDir = nullptr;
152 procDir = OpenDestDir(path_);
153 if (procDir == nullptr) {
154 return false;
155 }
156
157 uint32_t i = 0;
158 while (int32_t tid = GetValidTid(procDir)) {
159 if (tid <= 0) {
160 closedir(procDir);
161 PROFILER_LOG_WARN(LOG_CORE, "%s: get pid[%d] failed", __func__, tid);
162 return false;
163 }
164 i++;
165 }
166 cpuData.set_process_num(i);
167 closedir(procDir);
168
169 return true;
170 }
171
Stop()172 int CpuDataPlugin::Stop()
173 {
174 if (buffer_ != nullptr) {
175 free(buffer_);
176 buffer_ = nullptr;
177 }
178
179 tidVec_.clear();
180 prevThreadCpuTimeMap_.clear();
181 prevCoreSystemCpuTimeMap_.clear();
182 prevCoreSystemBootTimeMap_.clear();
183 PROFILER_LOG_INFO(LOG_CORE, "%s:stop success!", __func__);
184 return 0;
185 }
186
ReadFile(std::string & fileName)187 int32_t CpuDataPlugin::ReadFile(std::string& fileName)
188 {
189 int fd = -1;
190 ssize_t bytesRead = 0;
191 char filePath[PATH_MAX + 1] = {0};
192 char realPath[PATH_MAX + 1] = {0};
193
194 if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s", fileName.c_str()) < 0) {
195 const int bufSize = 256;
196 char buf[bufSize] = { 0 };
197 strerror_r(errno, buf, bufSize);
198 PROFILER_LOG_ERROR(LOG_CORE, "snprintf_s(%s) error, errno(%d:%s)", fileName.c_str(), errno, buf);
199 return RET_FAIL;
200 }
201 if (realpath(filePath, realPath) == nullptr) {
202 const int bufSize = 256;
203 char buf[bufSize] = { 0 };
204 strerror_r(errno, buf, bufSize);
205 PROFILER_LOG_ERROR(LOG_CORE, "realpath(%s) failed, errno(%d:%s)", fileName.c_str(), errno, buf);
206 return RET_FAIL;
207 }
208
209 fd = open(realPath, O_RDONLY | O_CLOEXEC);
210 if (fd == -1) {
211 const int bufSize = 256;
212 char buf[bufSize] = { 0 };
213 strerror_r(errno, buf, bufSize);
214 PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, realPath, errno, buf);
215 err_ = errno;
216 return RET_FAIL;
217 }
218 if (buffer_ == nullptr) {
219 PROFILER_LOG_ERROR(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
220 err_ = RET_NULL_ADDR;
221 close(fd);
222 return RET_FAIL;
223 }
224 if (memset_s(buffer_, READ_BUFFER_SIZE, 0, READ_BUFFER_SIZE) != EOK) {
225 PROFILER_LOG_ERROR(LOG_CORE, "%s:memset_s error!", __func__);
226 }
227 bytesRead = read(fd, buffer_, READ_BUFFER_SIZE - 1);
228 if (bytesRead <= 0) {
229 close(fd);
230 PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, realPath, errno);
231 err_ = errno;
232 return RET_FAIL;
233 }
234 close(fd);
235
236 return bytesRead;
237 }
238
SetTimestamp(T & sampleTimeStamp)239 template <typename T> void CpuDataPlugin::SetTimestamp(T& sampleTimeStamp)
240 {
241 timespec time;
242 clock_gettime(CLOCK_MONOTONIC, &time);
243 sampleTimeStamp.set_tv_sec(time.tv_sec);
244 sampleTimeStamp.set_tv_nsec(time.tv_nsec);
245 }
246
GetUserHz()247 int64_t CpuDataPlugin::GetUserHz()
248 {
249 int64_t hz = -1;
250 int64_t user_hz = sysconf(_SC_CLK_TCK);
251 switch (user_hz) {
252 case CPU_USER_HZ_L:
253 hz = CPU_HZ_H;
254 break;
255 case CPU_USER_HZ_H:
256 hz = 1;
257 break;
258 default:
259 break;
260 }
261 return hz;
262 }
263
GetCpuUsageTime(std::vector<std::string> & cpuUsageVec)264 int64_t CpuDataPlugin::GetCpuUsageTime(std::vector<std::string>& cpuUsageVec)
265 {
266 int64_t utime = 0;
267 int64_t stime = 0;
268 int64_t usageTime = 0;
269 if ((!COMMON::IsNumeric(cpuUsageVec[PROCESS_UTIME])) || (!COMMON::IsNumeric(cpuUsageVec[PROCESS_STIME]))) {
270 return 0;
271 }
272 utime = atoi(cpuUsageVec[PROCESS_UTIME].c_str());
273 stime = atoi(cpuUsageVec[PROCESS_STIME].c_str());
274 // 进程,线程CPU占用率只计算utime(用户态时间),stime(核心态时间)
275 usageTime = (utime + stime) * GetUserHz();
276
277 return usageTime;
278 }
279
WriteProcessCpuUsage(T & cpuUsageInfo,const char * pFile,uint32_t fileLen)280 template <typename T> void CpuDataPlugin::WriteProcessCpuUsage(T& cpuUsageInfo, const char* pFile, uint32_t fileLen)
281 {
282 BufferSplitter totalbuffer(const_cast<char*>(pFile), fileLen + 1);
283 std::vector<std::string> cpuUsageVec;
284 for (int i = 0; i < STAT_COUNT; i++) {
285 totalbuffer.NextWord(' ');
286 if (!totalbuffer.CurWord()) {
287 return;
288 }
289
290 if (i < STAT_START) {
291 continue;
292 } else {
293 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
294 cpuUsageVec.push_back(curWord);
295 }
296 }
297
298 // 获取到的数据不包含utime、stime、cutime、cstime四个数值时返回
299 if (cpuUsageVec.size() != PROCESS_UNSPECIFIED) {
300 PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to get process cpu usage, size=%zu", __func__, cpuUsageVec.size());
301 return;
302 }
303
304 int64_t usageTime = GetCpuUsageTime(cpuUsageVec);
305 cpuUsageInfo.set_prev_process_cpu_time_ms(prevProcessCpuTime_);
306 cpuUsageInfo.set_process_cpu_time_ms(usageTime);
307 prevProcessCpuTime_ = usageTime;
308 }
309
GetCpuFrequency(std::string fileName)310 int32_t CpuDataPlugin::GetCpuFrequency(std::string fileName)
311 {
312 int32_t frequency = 0;
313 int32_t ret = ReadFile(fileName);
314 if (ret != RET_FAIL) {
315 std::string tempStr(static_cast<char*>(buffer_));
316 // 去掉首尾特殊字符
317 size_t start = tempStr.find_first_not_of(" \t\n\r");
318 if (start == std::string::npos) {
319 return frequency;
320 }
321 size_t end = tempStr.find_last_not_of(" \t\n\r");
322 tempStr = tempStr.substr(start, end - start + 1);
323 if (std::all_of(tempStr.begin(), tempStr.end(), ::isdigit)) {
324 frequency = atoi(static_cast<char*>(buffer_));
325 }
326 }
327 return frequency;
328 }
329
GetCpuCoreSize()330 int CpuDataPlugin::GetCpuCoreSize()
331 {
332 int coreSize = 0;
333 DIR* procDir = nullptr;
334 procDir = OpenDestDir(freqPath_);
335 CHECK_NOTNULL(procDir, -1, "procDir is nullptr");
336
337 while (struct dirent* dirEnt = readdir(procDir)) {
338 if (dirEnt->d_type != DT_DIR) {
339 continue;
340 }
341 if (strncmp(dirEnt->d_name, "cpu", strlen("cpu")) == 0) {
342 coreSize++;
343 }
344 }
345 closedir(procDir);
346 return coreSize;
347 }
348
GetMaxCpuFrequencyIndex()349 int32_t CpuDataPlugin::GetMaxCpuFrequencyIndex()
350 {
351 int coreSize = GetCpuCoreSize();
352 int index = -1;
353 int32_t maxFreq = -1;
354 maxFrequencyVec_.clear();
355 minFrequencyVec_.clear();
356 for (int i = 0; i < coreSize; i++) {
357 std::string fileName = freqPath_ + "/cpu" + std::to_string(i) + FREQUENCY_MAX_PATH;
358 int32_t maxFrequency = GetCpuFrequency(fileName);
359 maxFrequencyVec_.push_back(maxFrequency);
360 fileName = freqPath_ + "/cpu" + std::to_string(i) + FREQUENCY_MIN_PATH;
361 int32_t minFrequency = GetCpuFrequency(fileName);
362 minFrequencyVec_.push_back(minFrequency);
363
364 if (maxFreq < maxFrequency) {
365 maxFreq = maxFrequency;
366 index = i;
367 }
368 }
369
370 // 单核或所有核最大频率相同,默认小核
371 if (coreSize == 1 || (coreSize > 1 && index == 0 && maxFreq == maxFrequencyVec_[1])) {
372 index = -1;
373 }
374
375 return index;
376 }
377
SetCpuFrequency(T & cpuCoreUsageInfo,int32_t coreNum)378 template <typename T> void CpuDataPlugin::SetCpuFrequency(T& cpuCoreUsageInfo, int32_t coreNum)
379 {
380 // 第一次获取最大频率核位置,并保存各核最大最小频率到vector
381 if (maxFrequencyVec_.empty() || minFrequencyVec_.empty()) {
382 maxFreqIndex_ = GetMaxCpuFrequencyIndex();
383 }
384 std::string fileName = freqPath_ + "/cpu" + std::to_string(coreNum) + FREQUENCY_CUR_PATH;
385 int32_t curFrequency = GetCpuFrequency(fileName);
386 int32_t maxFrequency = maxFrequencyVec_[coreNum];
387 int32_t minFrequency = minFrequencyVec_[coreNum];
388
389 if (coreNum == maxFreqIndex_) {
390 cpuCoreUsageInfo.set_is_little_core(false);
391 } else {
392 cpuCoreUsageInfo.set_is_little_core(true);
393 }
394 auto* frequency = cpuCoreUsageInfo.mutable_frequency();
395 frequency->set_min_frequency_khz(minFrequency);
396 frequency->set_max_frequency_khz(maxFrequency);
397 frequency->set_cur_frequency_khz(curFrequency);
398 }
399
GetSystemCpuTime(std::vector<std::string> & cpuUsageVec,CpuTimeData & cpuTimeData)400 bool CpuDataPlugin::GetSystemCpuTime(std::vector<std::string>& cpuUsageVec, CpuTimeData& cpuTimeData)
401 {
402 // 获取到的数据不包含user, nice, system, idle, iowait, irq, softirq, steal八个数值时返回
403 CHECK_TRUE(cpuUsageVec.size() == SYSTEM_UNSPECIFIED, false,
404 "%s:failed to get system cpu usage, size=%zu", __func__, cpuUsageVec.size());
405 if ((!COMMON::IsNumeric(cpuUsageVec[SYSTEM_USER])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_NICE])) ||
406 (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_SYSTEM])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_IDLE])) ||
407 (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_IOWAIT])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_IRQ])) ||
408 (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_SOFTIRQ])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_STEAL]))) {
409 return false;
410 }
411 int64_t user = 0;
412 int64_t nice = 0;
413 int64_t system = 0;
414 int64_t idle = 0;
415 int64_t iowait = 0;
416 int64_t irq = 0;
417 int64_t softirq = 0;
418 int64_t steal = 0;
419 user = atoi(cpuUsageVec[SYSTEM_USER].c_str());
420 nice = atoi(cpuUsageVec[SYSTEM_NICE].c_str());
421 system = atoi(cpuUsageVec[SYSTEM_SYSTEM].c_str());
422 idle = atoi(cpuUsageVec[SYSTEM_IDLE].c_str());
423 iowait = atoi(cpuUsageVec[SYSTEM_IOWAIT].c_str());
424 irq = atoi(cpuUsageVec[SYSTEM_IRQ].c_str());
425 softirq = atoi(cpuUsageVec[SYSTEM_SOFTIRQ].c_str());
426 steal = atoi(cpuUsageVec[SYSTEM_STEAL].c_str());
427
428 cpuTimeData.userModeUsageTime = user * GetUserHz();
429 cpuTimeData.systemModeUsageTime = system * GetUserHz();
430 cpuTimeData.systemUsageTime = (user + nice + system + irq + softirq + steal) * GetUserHz();
431 cpuTimeData.systemBootTime = cpuTimeData.systemUsageTime + (idle + iowait) * GetUserHz();
432 return true;
433 }
434
435 template <typename T>
WriteSystemCpuUsage(T & cpuUsageInfo,CpuLoadData & cpuLoadData,const char * pFile,uint32_t fileLen)436 void CpuDataPlugin::WriteSystemCpuUsage(T& cpuUsageInfo, CpuLoadData& cpuLoadData, const char* pFile, uint32_t fileLen)
437 {
438 std::vector<std::string> cpuUsageVec;
439 size_t cpuLength = strlen("cpu");
440 std::stringstream ss(pFile);
441 std::string line;
442 while (std::getline(ss, line)) {
443 BufferSplitter totalbuffer(const_cast<char*>(line.c_str()), line.length());
444 totalbuffer.NextWord(' ');
445 if (!totalbuffer.CurWord() || strncmp(totalbuffer.CurWord(), "cpu", cpuLength) != 0) {
446 return;
447 }
448
449 for (int i = 0; i < SYSTEM_STAT_COUNT; i++) {
450 if (!totalbuffer.CurWord()) {
451 return;
452 }
453 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
454 cpuUsageVec.push_back(curWord);
455 totalbuffer.NextWord(' ');
456 }
457
458 // 获取数据失败返回
459 CpuTimeData cpuTimeData;
460 if (!GetSystemCpuTime(cpuUsageVec, cpuTimeData)) {
461 return;
462 }
463
464 if (strcmp(cpuUsageVec[0].c_str(), "cpu") == 0) {
465 cpuUsageInfo.set_prev_system_cpu_time_ms(prevCpuTimeData_.systemUsageTime);
466 cpuUsageInfo.set_prev_system_boot_time_ms(prevCpuTimeData_.systemBootTime);
467 cpuUsageInfo.set_system_cpu_time_ms(cpuTimeData.systemUsageTime);
468 cpuUsageInfo.set_system_boot_time_ms(cpuTimeData.systemBootTime);
469 bool isTest = false;
470 if (strncmp(path_.c_str(), "/proc/", strlen("/proc/")) != 0) {
471 isTest = true; // UT needs report load data for the first time
472 }
473 if ((protoConfig_.report_process_info() && prevCpuTimeData_.systemBootTime != 0) || isTest) {
474 cpuLoadData.userLoad = static_cast<double>(cpuTimeData.userModeUsageTime -
475 prevCpuTimeData_.userModeUsageTime) /
476 static_cast<double>(cpuTimeData.systemBootTime -
477 prevCpuTimeData_.systemBootTime) * PERCENT;
478 cpuLoadData.sysLoad = static_cast<double>(cpuTimeData.systemModeUsageTime -
479 prevCpuTimeData_.systemModeUsageTime) /
480 static_cast<double>(cpuTimeData.systemBootTime -
481 prevCpuTimeData_.systemBootTime) * PERCENT;
482 cpuLoadData.totalLoad = static_cast<double>(cpuTimeData.systemUsageTime -
483 prevCpuTimeData_.systemUsageTime) /
484 static_cast<double>(cpuTimeData.systemBootTime -
485 prevCpuTimeData_.systemBootTime) * PERCENT;
486 }
487 prevCpuTimeData_ = cpuTimeData;
488 if (pid_ < 0 && protoConfig_.report_process_info()) {
489 return;
490 }
491 } else {
492 std::string core = std::string(cpuUsageVec[0].c_str() + cpuLength, cpuUsageVec[0].size() - cpuLength);
493 if (!COMMON::IsNumeric(core)) {
494 PROFILER_LOG_ERROR(LOG_CORE, "WriteSystemCpuUsage core is not numeric");
495 return;
496 }
497 int32_t coreNum = atoi(core.c_str());
498 // 第一次获取数据时需要将前一个数据置为0
499 if (prevCoreSystemCpuTimeMap_.size() == static_cast<size_t>(coreNum)) {
500 prevCoreSystemCpuTimeMap_[coreNum] = 0;
501 prevCoreSystemBootTimeMap_[coreNum] = 0;
502 }
503 auto* cpuCore = cpuUsageInfo.add_cores();
504 cpuCore->set_cpu_core(coreNum);
505 cpuCore->set_prev_system_cpu_time_ms(prevCoreSystemCpuTimeMap_[coreNum]);
506 cpuCore->set_prev_system_boot_time_ms(prevCoreSystemBootTimeMap_[coreNum]);
507 cpuCore->set_system_cpu_time_ms(cpuTimeData.systemUsageTime);
508 cpuCore->set_system_boot_time_ms(cpuTimeData.systemBootTime);
509
510 SetCpuFrequency(*cpuCore, coreNum);
511 prevCoreSystemCpuTimeMap_[coreNum] = cpuTimeData.systemUsageTime;
512 prevCoreSystemBootTimeMap_[coreNum] = cpuTimeData.systemBootTime;
513 }
514
515 cpuUsageVec.clear();
516 }
517 }
518
WriteCpuUsageInfo(T & cpuData,I cpuUsageInfo)519 template <typename T, typename I> void CpuDataPlugin::WriteCpuUsageInfo(T& cpuData, I cpuUsageInfo)
520 {
521 // write process info
522 if (pid_ > 0) {
523 std::string fileName = path_ + std::to_string(pid_) + "/stat";
524 int32_t ret = ReadFile(fileName);
525 if (ret == RET_FAIL) {
526 return;
527 }
528 if ((buffer_ == nullptr) || (ret == 0)) {
529 return;
530 }
531
532 cpuUsageInfo = cpuData.mutable_cpu_usage_info();
533 WriteProcessCpuUsage(*cpuUsageInfo, reinterpret_cast<char*>(buffer_), ret);
534 }
535
536 // write system info
537 std::string fileName = path_ + "stat";
538 int32_t ret = ReadFile(fileName);
539 if (ret == RET_FAIL) {
540 return;
541 }
542 if ((buffer_ == nullptr) || (ret == 0)) {
543 return;
544 }
545
546 CpuLoadData cpuLoadData;
547 if (cpuUsageInfo == nullptr) {
548 cpuUsageInfo = cpuData.mutable_cpu_usage_info();
549 }
550 WriteSystemCpuUsage(*cpuUsageInfo, cpuLoadData, reinterpret_cast<char*>(buffer_), ret);
551
552 auto* timestamp = cpuUsageInfo->mutable_timestamp();
553 SetTimestamp(*timestamp);
554
555 cpuData.set_user_load(cpuLoadData.userLoad);
556 cpuData.set_sys_load(cpuLoadData.sysLoad);
557 cpuData.set_total_load(cpuLoadData.totalLoad);
558 }
559
addTidBySort(int32_t tid)560 bool CpuDataPlugin::addTidBySort(int32_t tid)
561 {
562 auto tidsEnd = tidVec_.end();
563 auto it = std::lower_bound(tidVec_.begin(), tidsEnd, tid);
564 CHECK_TRUE(!(it != tidsEnd && *it == tid), false, "addTidBySort failed");
565 it = tidVec_.insert(it, std::move(tid));
566 return true;
567 }
568
OpenDestDir(std::string & dirPath)569 DIR* CpuDataPlugin::OpenDestDir(std::string& dirPath)
570 {
571 DIR* destDir = nullptr;
572
573 destDir = opendir(dirPath.c_str());
574 CHECK_NOTNULL(destDir, nullptr, "%s:failed to opendir(%s), errno=%d", __func__, dirPath.c_str(), errno);
575
576 return destDir;
577 }
578
GetValidTid(DIR * dirp)579 int32_t CpuDataPlugin::GetValidTid(DIR* dirp)
580 {
581 CHECK_TRUE(dirp, 0, "dirp is nullptr");
582 while (struct dirent* dirEnt = readdir(dirp)) {
583 if (dirEnt->d_type != DT_DIR) {
584 continue;
585 }
586 if (!COMMON::IsNumeric(std::string(dirEnt->d_name))) {
587 continue;
588 }
589 int32_t tid = atoi(dirEnt->d_name);
590 if (tid) {
591 return tid;
592 }
593 }
594 return 0;
595 }
596
GetThreadState(const char threadState)597 ThreadState CpuDataPlugin::GetThreadState(const char threadState)
598 {
599 ThreadState state = THREAD_UNSPECIFIED;
600 switch (threadState) {
601 case 'R':
602 state = THREAD_RUNNING;
603 break;
604 case 'S':
605 state = THREAD_SLEEPING;
606 break;
607 case 'T':
608 state = THREAD_STOPPED;
609 break;
610 case 'D':
611 state = THREAD_WAITING;
612 break;
613 default:
614 break;
615 }
616
617 return state;
618 }
619
WriteThread(T & threadInfo,const char * pFile,uint32_t fileLen,int32_t tid)620 template <typename T> void CpuDataPlugin::WriteThread(T& threadInfo, const char* pFile, uint32_t fileLen, int32_t tid)
621 {
622 BufferSplitter totalbuffer(const_cast<char*>(pFile), fileLen + 1);
623 std::vector<std::string> cpuUsageVec;
624 for (int i = 0; i < STAT_COUNT; i++) {
625 if (i == THREAD_NAME_POS) { // 线程名是')'作为结束符
626 totalbuffer.NextWord(')');
627 } else {
628 totalbuffer.NextWord(' ');
629 }
630
631 if (!totalbuffer.CurWord()) {
632 return;
633 }
634
635 if (i == THREAD_NAME_POS) {
636 size_t nameLeng = totalbuffer.CurWordSize() > 1 ? static_cast<size_t>(totalbuffer.CurWordSize() - 1) : 0;
637 std::string curWord = std::string(totalbuffer.CurWord() + 1, nameLeng);
638 threadInfo.set_thread_name(curWord);
639 } else if (i == THREAD_STATE_POS) {
640 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
641 ThreadState state = GetThreadState(curWord[0]);
642 threadInfo.set_thread_state(state);
643 } else if (i >= STAT_START) {
644 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
645 cpuUsageVec.push_back(curWord);
646 }
647 }
648
649 // 获取到的数据不包含utime、stime、cutime、cstime四个数值时返回
650 if (cpuUsageVec.size() != PROCESS_UNSPECIFIED) {
651 PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to get thread cpu usage, size=%zu", __func__, cpuUsageVec.size());
652 return;
653 }
654
655 // 第一次获取该线程数据时需要将前一个数据置为0
656 if (prevThreadCpuTimeMap_.find(tid) == prevThreadCpuTimeMap_.end()) {
657 prevThreadCpuTimeMap_[tid] = 0;
658 }
659
660 int64_t usageTime = GetCpuUsageTime(cpuUsageVec);
661 threadInfo.set_prev_thread_cpu_time_ms(prevThreadCpuTimeMap_[tid]);
662 threadInfo.set_thread_cpu_time_ms(usageTime);
663 prevThreadCpuTimeMap_[tid] = usageTime;
664 threadInfo.set_tid(tid);
665
666 auto* timestamp = threadInfo.mutable_timestamp();
667 SetTimestamp(*timestamp);
668 }
669
WriteSingleThreadInfo(T & cpuData,int32_t tid)670 template <typename T> void CpuDataPlugin::WriteSingleThreadInfo(T& cpuData, int32_t tid)
671 {
672 std::string fileName = path_ + std::to_string(pid_) + "/task/" + std::to_string(tid) + "/stat";
673 int32_t ret = ReadFile(fileName);
674 if (ret == RET_FAIL) {
675 return;
676 }
677 if ((buffer_ == nullptr) || (ret == 0)) {
678 return;
679 }
680 auto* threadInfo = cpuData.add_thread_info();
681 WriteThread(*threadInfo, reinterpret_cast<char*>(buffer_), ret, tid);
682 }
683
WriteThreadInfo(T & cpuData)684 template <typename T> void CpuDataPlugin::WriteThreadInfo(T& cpuData)
685 {
686 DIR* procDir = nullptr;
687 std::string path = path_ + std::to_string(pid_) + "/task";
688 procDir = OpenDestDir(path);
689 if (procDir == nullptr) {
690 return;
691 }
692
693 tidVec_.clear();
694 while (int32_t tid = GetValidTid(procDir)) {
695 addTidBySort(tid);
696 }
697
698 for (unsigned int i = 0; i < tidVec_.size(); i++) {
699 WriteSingleThreadInfo(cpuData, tidVec_[i]);
700 }
701 closedir(procDir);
702 }
703
704 // for UT
SetFreqPath(std::string path)705 void CpuDataPlugin::SetFreqPath(std::string path)
706 {
707 freqPath_ = path + FREQUENCY_PATH;
708 }
709