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