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