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