* Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cpu_data_plugin.h"
#include <ctime>
#include <vector>
#include <sstream>
#include "common.h"
#include "cpu_plugin_result.pbencoder.h"
#include "buffer_splitter.h"
namespace {
using namespace OHOS::Developtools::Profiler;
constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
constexpr int SYSTEM_STAT_COUNT = 9;
constexpr int STAT_COUNT = 17;
constexpr int STAT_START = 13;
constexpr int THREAD_NAME_POS = 1;
constexpr int THREAD_STATE_POS = 2;
constexpr int CPU_USER_HZ_L = 100;
constexpr int CPU_USER_HZ_H = 1000;
constexpr int CPU_HZ_H = 10;
const int PERCENT = 100;
const std::string FREQUENCY_PATH = "/sys/devices/system/cpu";
const std::string FREQUENCY_MIN_PATH = "/cpufreq/cpuinfo_min_freq";
const std::string FREQUENCY_MAX_PATH = "/cpufreq/cpuinfo_max_freq";
const std::string FREQUENCY_CUR_PATH = "/cpufreq/cpuinfo_cur_freq";
}
CpuDataPlugin::CpuDataPlugin()
{
buffer_ = nullptr;
path_ = "/proc/";
err_ = -1;
pid_ = -1;
prevProcessCpuTime_ = 0;
prevCpuTimeData_ = {};
maxFreqIndex_ = -1;
freqPath_ = FREQUENCY_PATH;
}
CpuDataPlugin::~CpuDataPlugin()
{
PROFILER_LOG_INFO(LOG_CORE, "%s:~CpuDataPlugin!", __func__);
if (buffer_ != nullptr) {
free(buffer_);
buffer_ = nullptr;
}
tidVec_.clear();
prevThreadCpuTimeMap_.clear();
prevCoreSystemCpuTimeMap_.clear();
prevCoreSystemBootTimeMap_.clear();
maxFrequencyVec_.clear();
minFrequencyVec_.clear();
}
std::string CpuDataPlugin::GetCmdArgs(const CpuConfig& protoConfig)
{
std::stringstream args;
args << "pid: " << COMMON::GetProcessNameByPid(protoConfig.pid());
args << " report_process_info: " << (protoConfig.report_process_info() ? "true" : "false");
return args.str();
}
int CpuDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
{
buffer_ = malloc(READ_BUFFER_SIZE);
CHECK_NOTNULL(buffer_, RET_FAIL, "%s:malloc buffer_ failed!", __func__);
if (memset_s(buffer_, READ_BUFFER_SIZE, 0, READ_BUFFER_SIZE) != EOK) {
PROFILER_LOG_ERROR(LOG_CORE, "%s:memset_s error!", __func__);
}
CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
"%s:parseFromArray failed!", __func__);
auto args = GetCmdArgs(protoConfig_);
if (protoConfig_.pid() > 0) {
pid_ = protoConfig_.pid();
} else if (protoConfig_.report_process_info()) {
PROFILER_LOG_INFO(LOG_CORE, "%s:need report process info", __func__);
} else {
int ret = COMMON::PluginWriteToHisysevent("CPU_PLUGIN", "sh", args, RET_FAIL, "failed");
PROFILER_LOG_ERROR(LOG_CORE, "%s:invalid pid, record hisysevent result. %d", __func__, ret);
return RET_FAIL;
}
int ret = COMMON::PluginWriteToHisysevent("cpu_plugin", "sh", args, RET_SUCC, "success");
PROFILER_LOG_INFO(LOG_CORE, "%s:start success! hisysevent report cpu_plugin result: %d", __func__, ret);
return RET_SUCC;
}
int CpuDataPlugin::ReportOptimize(RandomWriteCtx* randomWrite)
{
ProtoEncoder::CpuData dataProto(randomWrite);
ProtoEncoder::CpuUsageInfo* cpuUsageInfo = nullptr;
WriteCpuUsageInfo(dataProto, cpuUsageInfo);
if (pid_ > 0 && (!protoConfig_.skip_thread_cpu_info())) {
WriteThreadInfo(dataProto);
}
if (protoConfig_.report_process_info()) {
WriteProcnum(dataProto);
}
int msgSize = dataProto.Finish();
return msgSize;
}
int CpuDataPlugin::Report(uint8_t* data, uint32_t dataSize)
{
CpuData dataProto;
uint32_t length;
CpuUsageInfo* cpuUsageInfo = nullptr;
WriteCpuUsageInfo(dataProto, cpuUsageInfo);
if (pid_ > 0 && (!protoConfig_.skip_thread_cpu_info())) {
WriteThreadInfo(dataProto);
}
if (protoConfig_.report_process_info()) {
WriteProcnum(dataProto);
}
length = dataProto.ByteSizeLong();
if (length > dataSize) {
return -length;
}
if (dataProto.SerializeToArray(data, length) > 0) {
return length;
}
return 0;
}
template <typename T> bool CpuDataPlugin::WriteProcnum(T& cpuData)
{
DIR* procDir = nullptr;
procDir = OpenDestDir(path_);
if (procDir == nullptr) {
return false;
}
uint32_t i = 0;
while (int32_t tid = GetValidTid(procDir)) {
if (tid <= 0) {
closedir(procDir);
PROFILER_LOG_WARN(LOG_CORE, "%s: get pid[%d] failed", __func__, tid);
return false;
}
i++;
}
cpuData.set_process_num(i);
closedir(procDir);
return true;
}
int CpuDataPlugin::Stop()
{
if (buffer_ != nullptr) {
free(buffer_);
buffer_ = nullptr;
}
tidVec_.clear();
prevThreadCpuTimeMap_.clear();
prevCoreSystemCpuTimeMap_.clear();
prevCoreSystemBootTimeMap_.clear();
PROFILER_LOG_INFO(LOG_CORE, "%s:stop success!", __func__);
return 0;
}
int32_t CpuDataPlugin::ReadFile(std::string& fileName)
{
ssize_t bytesRead = 0;
char filePath[PATH_MAX + 1] = {0};
char realPath[PATH_MAX + 1] = {0};
if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s", fileName.c_str()) < 0) {
const int bufSize = 256;
char buf[bufSize] = { 0 };
strerror_r(errno, buf, bufSize);
PROFILER_LOG_ERROR(LOG_CORE, "snprintf_s(%s) error, errno(%d:%s)", fileName.c_str(), errno, buf);
return RET_FAIL;
}
if (realpath(filePath, realPath) == nullptr) {
const int bufSize = 256;
char buf[bufSize] = { 0 };
strerror_r(errno, buf, bufSize);
PROFILER_LOG_ERROR(LOG_CORE, "realpath(%s) failed, errno(%d:%s)", fileName.c_str(), errno, buf);
return RET_FAIL;
}
FILE *fp = fopen(realPath, "rb");
if (fp == nullptr) {
const int bufSize = 256;
char buf[bufSize] = { 0 };
strerror_r(errno, buf, bufSize);
PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, realPath, errno, buf);
err_ = errno;
return RET_FAIL;
}
if (buffer_ == nullptr) {
PROFILER_LOG_ERROR(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
err_ = RET_NULL_ADDR;
fclose(fp);
return RET_FAIL;
}
if (memset_s(buffer_, READ_BUFFER_SIZE, 0, READ_BUFFER_SIZE) != EOK) {
PROFILER_LOG_ERROR(LOG_CORE, "%s:memset_s error!", __func__);
}
bytesRead = fread(buffer_, sizeof(char), READ_BUFFER_SIZE - 1, fp);
if (bytesRead <= 0) {
fclose(fp);
PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, realPath, errno);
err_ = errno;
return RET_FAIL;
}
if (fclose(fp) != 0) {
PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to close(%s)", __func__, realPath);
}
return bytesRead;
}
template <typename T> void CpuDataPlugin::SetTimestamp(T& sampleTimeStamp)
{
timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
sampleTimeStamp.set_tv_sec(time.tv_sec);
sampleTimeStamp.set_tv_nsec(time.tv_nsec);
}
int64_t CpuDataPlugin::GetUserHz()
{
int64_t hz = -1;
int64_t user_hz = sysconf(_SC_CLK_TCK);
switch (user_hz) {
case CPU_USER_HZ_L:
hz = CPU_HZ_H;
break;
case CPU_USER_HZ_H:
hz = 1;
break;
default:
break;
}
return hz;
}
int64_t CpuDataPlugin::GetCpuUsageTime(std::vector<std::string>& cpuUsageVec)
{
int64_t utime = 0;
int64_t stime = 0;
int64_t usageTime = 0;
if ((!COMMON::IsNumeric(cpuUsageVec[PROCESS_UTIME])) || (!COMMON::IsNumeric(cpuUsageVec[PROCESS_STIME]))) {
return 0;
}
utime = atoi(cpuUsageVec[PROCESS_UTIME].c_str());
stime = atoi(cpuUsageVec[PROCESS_STIME].c_str());
usageTime = (utime + stime) * GetUserHz();
return usageTime;
}
template <typename T> void CpuDataPlugin::WriteProcessCpuUsage(T& cpuUsageInfo, const char* pFile, uint32_t fileLen)
{
BufferSplitter totalbuffer(const_cast<char*>(pFile), fileLen + 1);
std::vector<std::string> cpuUsageVec;
for (int i = 0; i < STAT_COUNT; i++) {
totalbuffer.NextWord(' ');
if (!totalbuffer.CurWord()) {
return;
}
if (i < STAT_START) {
continue;
} else {
std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
cpuUsageVec.push_back(curWord);
}
}
if (cpuUsageVec.size() != PROCESS_UNSPECIFIED) {
PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to get process cpu usage, size=%zu", __func__, cpuUsageVec.size());
return;
}
int64_t usageTime = GetCpuUsageTime(cpuUsageVec);
cpuUsageInfo.set_prev_process_cpu_time_ms(prevProcessCpuTime_);
cpuUsageInfo.set_process_cpu_time_ms(usageTime);
prevProcessCpuTime_ = usageTime;
}
int32_t CpuDataPlugin::GetCpuFrequency(std::string fileName)
{
int32_t frequency = 0;
int32_t ret = ReadFile(fileName);
if (ret != RET_FAIL) {
std::string tempStr(static_cast<char*>(buffer_));
size_t start = tempStr.find_first_not_of(" \t\n\r");
if (start == std::string::npos) {
return frequency;
}
size_t end = tempStr.find_last_not_of(" \t\n\r");
tempStr = tempStr.substr(start, end - start + 1);
if (std::all_of(tempStr.begin(), tempStr.end(), ::isdigit)) {
frequency = atoi(static_cast<char*>(buffer_));
}
}
return frequency;
}
int CpuDataPlugin::GetCpuCoreSize()
{
int coreSize = 0;
DIR* procDir = nullptr;
procDir = OpenDestDir(freqPath_);
CHECK_NOTNULL(procDir, -1, "procDir is nullptr");
while (struct dirent* dirEnt = readdir(procDir)) {
if (dirEnt->d_type != DT_DIR) {
continue;
}
if (strncmp(dirEnt->d_name, "cpu", strlen("cpu")) == 0) {
coreSize++;
}
}
closedir(procDir);
return coreSize;
}
int32_t CpuDataPlugin::GetMaxCpuFrequencyIndex()
{
int coreSize = GetCpuCoreSize();
int index = -1;
int32_t maxFreq = -1;
maxFrequencyVec_.clear();
minFrequencyVec_.clear();
for (int i = 0; i < coreSize; i++) {
std::string fileName = freqPath_ + "/cpu" + std::to_string(i) + FREQUENCY_MAX_PATH;
int32_t maxFrequency = GetCpuFrequency(fileName);
maxFrequencyVec_.push_back(maxFrequency);
fileName = freqPath_ + "/cpu" + std::to_string(i) + FREQUENCY_MIN_PATH;
int32_t minFrequency = GetCpuFrequency(fileName);
minFrequencyVec_.push_back(minFrequency);
if (maxFreq < maxFrequency) {
maxFreq = maxFrequency;
index = i;
}
}
if (coreSize == 1 || (coreSize > 1 && index == 0 && maxFreq == maxFrequencyVec_[1])) {
index = -1;
}
return index;
}
template <typename T> void CpuDataPlugin::SetCpuFrequency(T& cpuCoreUsageInfo, int32_t coreNum)
{
if (maxFrequencyVec_.empty() || minFrequencyVec_.empty()) {
maxFreqIndex_ = GetMaxCpuFrequencyIndex();
}
std::string fileName = freqPath_ + "/cpu" + std::to_string(coreNum) + FREQUENCY_CUR_PATH;
int32_t curFrequency = GetCpuFrequency(fileName);
int32_t maxFrequency = maxFrequencyVec_[coreNum];
int32_t minFrequency = minFrequencyVec_[coreNum];
if (coreNum == maxFreqIndex_) {
cpuCoreUsageInfo.set_is_little_core(false);
} else {
cpuCoreUsageInfo.set_is_little_core(true);
}
auto* frequency = cpuCoreUsageInfo.mutable_frequency();
frequency->set_min_frequency_khz(minFrequency);
frequency->set_max_frequency_khz(maxFrequency);
frequency->set_cur_frequency_khz(curFrequency);
}
bool CpuDataPlugin::GetSystemCpuTime(std::vector<std::string>& cpuUsageVec, CpuTimeData& cpuTimeData)
{
CHECK_TRUE(cpuUsageVec.size() == SYSTEM_UNSPECIFIED, false,
"%s:failed to get system cpu usage, size=%zu", __func__, cpuUsageVec.size());
if ((!COMMON::IsNumeric(cpuUsageVec[SYSTEM_USER])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_NICE])) ||
(!COMMON::IsNumeric(cpuUsageVec[SYSTEM_SYSTEM])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_IDLE])) ||
(!COMMON::IsNumeric(cpuUsageVec[SYSTEM_IOWAIT])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_IRQ])) ||
(!COMMON::IsNumeric(cpuUsageVec[SYSTEM_SOFTIRQ])) || (!COMMON::IsNumeric(cpuUsageVec[SYSTEM_STEAL]))) {
return false;
}
int64_t user = 0;
int64_t nice = 0;
int64_t system = 0;
int64_t idle = 0;
int64_t iowait = 0;
int64_t irq = 0;
int64_t softirq = 0;
int64_t steal = 0;
user = atoi(cpuUsageVec[SYSTEM_USER].c_str());
nice = atoi(cpuUsageVec[SYSTEM_NICE].c_str());
system = atoi(cpuUsageVec[SYSTEM_SYSTEM].c_str());
idle = atoi(cpuUsageVec[SYSTEM_IDLE].c_str());
iowait = atoi(cpuUsageVec[SYSTEM_IOWAIT].c_str());
irq = atoi(cpuUsageVec[SYSTEM_IRQ].c_str());
softirq = atoi(cpuUsageVec[SYSTEM_SOFTIRQ].c_str());
steal = atoi(cpuUsageVec[SYSTEM_STEAL].c_str());
cpuTimeData.userModeUsageTime = user * GetUserHz();
cpuTimeData.systemModeUsageTime = system * GetUserHz();
cpuTimeData.systemUsageTime = (user + nice + system + irq + softirq + steal) * GetUserHz();
cpuTimeData.systemBootTime = cpuTimeData.systemUsageTime + (idle + iowait) * GetUserHz();
return true;
}
template <typename T>
bool CpuDataPlugin::SetSystemCpuUsage(T& cpuUsageInfo, CpuLoadData& cpuLoadData, CpuTimeData& cpuTimeData)
{
cpuUsageInfo.set_prev_system_cpu_time_ms(prevCpuTimeData_.systemUsageTime);
cpuUsageInfo.set_prev_system_boot_time_ms(prevCpuTimeData_.systemBootTime);
cpuUsageInfo.set_system_cpu_time_ms(cpuTimeData.systemUsageTime);
cpuUsageInfo.set_system_boot_time_ms(cpuTimeData.systemBootTime);
bool isTest = false;
if (strncmp(path_.c_str(), "/proc/", strlen("/proc/")) != 0) {
isTest = true;
}
if ((protoConfig_.report_process_info() && prevCpuTimeData_.systemBootTime != 0) || isTest) {
cpuLoadData.userLoad = static_cast<double>(cpuTimeData.userModeUsageTime - prevCpuTimeData_.userModeUsageTime) /
static_cast<double>(cpuTimeData.systemBootTime - prevCpuTimeData_.systemBootTime) *
PERCENT;
cpuLoadData.sysLoad =
static_cast<double>(cpuTimeData.systemModeUsageTime - prevCpuTimeData_.systemModeUsageTime) /
static_cast<double>(cpuTimeData.systemBootTime - prevCpuTimeData_.systemBootTime) * PERCENT;
cpuLoadData.totalLoad = static_cast<double>(cpuTimeData.systemUsageTime - prevCpuTimeData_.systemUsageTime) /
static_cast<double>(cpuTimeData.systemBootTime - prevCpuTimeData_.systemBootTime) *
PERCENT;
}
prevCpuTimeData_ = cpuTimeData;
if (pid_ < 0 && protoConfig_.report_process_info()) {
return false;
}
return true;
}
template <typename T>
bool CpuDataPlugin::SetCpuCoreInfo(const std::string& cpuUsageStr, T& cpuUsageInfo, CpuTimeData& cpuTimeData)
{
size_t cpuLength = strlen("cpu");
std::string core = std::string(cpuUsageStr.c_str() + cpuLength, cpuUsageStr.size() - cpuLength);
if (!COMMON::IsNumeric(core)) {
PROFILER_LOG_ERROR(LOG_CORE, "WriteSystemCpuUsage core is not numeric");
return false;
}
int32_t coreNum = atoi(core.c_str());
if (prevCoreSystemCpuTimeMap_.size() == static_cast<size_t>(coreNum)) {
prevCoreSystemCpuTimeMap_[coreNum] = 0;
prevCoreSystemBootTimeMap_[coreNum] = 0;
}
auto* cpuCore = cpuUsageInfo.add_cores();
cpuCore->set_cpu_core(coreNum);
cpuCore->set_prev_system_cpu_time_ms(prevCoreSystemCpuTimeMap_[coreNum]);
cpuCore->set_prev_system_boot_time_ms(prevCoreSystemBootTimeMap_[coreNum]);
cpuCore->set_system_cpu_time_ms(cpuTimeData.systemUsageTime);
cpuCore->set_system_boot_time_ms(cpuTimeData.systemBootTime);
SetCpuFrequency(*cpuCore, coreNum);
prevCoreSystemCpuTimeMap_[coreNum] = cpuTimeData.systemUsageTime;
prevCoreSystemBootTimeMap_[coreNum] = cpuTimeData.systemBootTime;
return true;
}
template <typename T>
void CpuDataPlugin::WriteSystemCpuUsage(T& cpuUsageInfo, CpuLoadData& cpuLoadData, const char* pFile, uint32_t fileLen)
{
std::vector<std::string> cpuUsageVec;
size_t cpuLength = strlen("cpu");
std::stringstream ss(pFile);
std::string line;
while (std::getline(ss, line)) {
BufferSplitter totalbuffer(const_cast<char*>(line.c_str()), line.length());
totalbuffer.NextWord(' ');
if (!totalbuffer.CurWord() || strncmp(totalbuffer.CurWord(), "cpu", cpuLength) != 0) {
return;
}
for (int i = 0; i < SYSTEM_STAT_COUNT; i++) {
if (!totalbuffer.CurWord()) {
return;
}
std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
cpuUsageVec.push_back(curWord);
totalbuffer.NextWord(' ');
}
CpuTimeData cpuTimeData;
if (!GetSystemCpuTime(cpuUsageVec, cpuTimeData)) {
return;
}
if (strcmp(cpuUsageVec[0].c_str(), "cpu") == 0) {
if (!SetSystemCpuUsage(cpuUsageInfo, cpuLoadData, cpuTimeData)) {
return;
}
} else {
if (!SetCpuCoreInfo(cpuUsageVec[0], cpuUsageInfo, cpuTimeData)) {
return;
}
}
cpuUsageVec.clear();
}
}
template <typename T, typename I> void CpuDataPlugin::WriteCpuUsageInfo(T& cpuData, I cpuUsageInfo)
{
if (pid_ > 0) {
std::string fileName = path_ + std::to_string(pid_) + "/stat";
int32_t ret = ReadFile(fileName);
if (ret == RET_FAIL) {
return;
}
if ((buffer_ == nullptr) || (ret == 0)) {
return;
}
cpuUsageInfo = cpuData.mutable_cpu_usage_info();
WriteProcessCpuUsage(*cpuUsageInfo, reinterpret_cast<char*>(buffer_), ret);
}
std::string fileName = path_ + "stat";
int32_t ret = ReadFile(fileName);
if (ret == RET_FAIL) {
return;
}
if ((buffer_ == nullptr) || (ret == 0)) {
return;
}
CpuLoadData cpuLoadData;
if (cpuUsageInfo == nullptr) {
cpuUsageInfo = cpuData.mutable_cpu_usage_info();
}
WriteSystemCpuUsage(*cpuUsageInfo, cpuLoadData, reinterpret_cast<char*>(buffer_), ret);
auto* timestamp = cpuUsageInfo->mutable_timestamp();
SetTimestamp(*timestamp);
cpuData.set_user_load(cpuLoadData.userLoad);
cpuData.set_sys_load(cpuLoadData.sysLoad);
cpuData.set_total_load(cpuLoadData.totalLoad);
}
bool CpuDataPlugin::addTidBySort(int32_t tid)
{
auto tidsEnd = tidVec_.end();
auto it = std::lower_bound(tidVec_.begin(), tidsEnd, tid);
CHECK_TRUE(!(it != tidsEnd && *it == tid), false, "addTidBySort failed");
it = tidVec_.insert(it, std::move(tid));
return true;
}
DIR* CpuDataPlugin::OpenDestDir(std::string& dirPath)
{
DIR* destDir = nullptr;
destDir = opendir(dirPath.c_str());
CHECK_NOTNULL(destDir, nullptr, "%s:failed to opendir(%s), errno=%d", __func__, dirPath.c_str(), errno);
return destDir;
}
int32_t CpuDataPlugin::GetValidTid(DIR* dirp)
{
CHECK_TRUE(dirp, 0, "dirp is nullptr");
while (struct dirent* dirEnt = readdir(dirp)) {
if (dirEnt->d_type != DT_DIR) {
continue;
}
if (!COMMON::IsNumeric(std::string(dirEnt->d_name))) {
continue;
}
int32_t tid = atoi(dirEnt->d_name);
if (tid) {
return tid;
}
}
return 0;
}
ThreadState CpuDataPlugin::GetThreadState(const char threadState)
{
ThreadState state = THREAD_UNSPECIFIED;
switch (threadState) {
case 'R':
state = THREAD_RUNNING;
break;
case 'S':
state = THREAD_SLEEPING;
break;
case 'T':
state = THREAD_STOPPED;
break;
case 'D':
state = THREAD_WAITING;
break;
default:
break;
}
return state;
}
template <typename T> void CpuDataPlugin::WriteThread(T& threadInfo, const char* pFile, uint32_t fileLen, int32_t tid)
{
BufferSplitter totalbuffer(const_cast<char*>(pFile), fileLen + 1);
std::vector<std::string> cpuUsageVec;
for (int i = 0; i < STAT_COUNT; i++) {
if (i == THREAD_NAME_POS) {
totalbuffer.NextWord(')');
} else {
totalbuffer.NextWord(' ');
}
if (!totalbuffer.CurWord()) {
return;
}
if (i == THREAD_NAME_POS) {
size_t nameLeng = totalbuffer.CurWordSize() > 1 ? static_cast<size_t>(totalbuffer.CurWordSize() - 1) : 0;
std::string curWord = std::string(totalbuffer.CurWord() + 1, nameLeng);
threadInfo.set_thread_name(curWord);
} else if (i == THREAD_STATE_POS) {
std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
ThreadState state = GetThreadState(curWord[0]);
threadInfo.set_thread_state(state);
} else if (i >= STAT_START) {
std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
cpuUsageVec.push_back(curWord);
}
}
if (cpuUsageVec.size() != PROCESS_UNSPECIFIED) {
PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to get thread cpu usage, size=%zu", __func__, cpuUsageVec.size());
return;
}
if (prevThreadCpuTimeMap_.find(tid) == prevThreadCpuTimeMap_.end()) {
prevThreadCpuTimeMap_[tid] = 0;
}
int64_t usageTime = GetCpuUsageTime(cpuUsageVec);
threadInfo.set_prev_thread_cpu_time_ms(prevThreadCpuTimeMap_[tid]);
threadInfo.set_thread_cpu_time_ms(usageTime);
prevThreadCpuTimeMap_[tid] = usageTime;
threadInfo.set_tid(tid);
auto* timestamp = threadInfo.mutable_timestamp();
SetTimestamp(*timestamp);
}
template <typename T> void CpuDataPlugin::WriteSingleThreadInfo(T& cpuData, int32_t tid)
{
std::string fileName = path_ + std::to_string(pid_) + "/task/" + std::to_string(tid) + "/stat";
int32_t ret = ReadFile(fileName);
if (ret == RET_FAIL) {
return;
}
if ((buffer_ == nullptr) || (ret == 0)) {
return;
}
auto* threadInfo = cpuData.add_thread_info();
WriteThread(*threadInfo, reinterpret_cast<char*>(buffer_), ret, tid);
}
template <typename T> void CpuDataPlugin::WriteThreadInfo(T& cpuData)
{
DIR* procDir = nullptr;
std::string path = path_ + std::to_string(pid_) + "/task";
procDir = OpenDestDir(path);
if (procDir == nullptr) {
return;
}
tidVec_.clear();
while (int32_t tid = GetValidTid(procDir)) {
addTidBySort(tid);
}
for (unsigned int i = 0; i < tidVec_.size(); i++) {
WriteSingleThreadInfo(cpuData, tidVec_[i]);
}
closedir(procDir);
}
void CpuDataPlugin::SetFreqPath(std::string path)
{
freqPath_ = path + FREQUENCY_PATH;
}