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