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