• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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