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