• 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 #include "process_data_plugin.h"
16 
17 #include <fcntl.h>
18 #include <fstream>
19 #include <iostream>
20 #include <sstream>
21 
22 #include "buffer_splitter.h"
23 #include "common.h"
24 #include "hisysevent.h"
25 #include "process_plugin_result.pbencoder.h"
26 #include "securec.h"
27 
28 namespace {
29 using namespace OHOS::Developtools::Profiler;
30 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
31 constexpr int DEC_BASE = 10;
32 constexpr int STAT_COUNT = 13;
33 constexpr int CPU_USER_HZ_L = 100;
34 constexpr int CPU_USER_HZ_H = 1000;
35 constexpr int CPU_HZ_H = 10;
36 const int PERCENT = 100;
37 } // namespace
38 
ProcessDataPlugin()39 ProcessDataPlugin::ProcessDataPlugin() : err_(-1)
40 {
41     SetPath("/proc/");
42     buffer_ = std::make_unique<uint8_t[]>(READ_BUFFER_SIZE);
43 }
44 
~ProcessDataPlugin()45 ProcessDataPlugin::~ProcessDataPlugin()
46 {
47     PROFILER_LOG_INFO(LOG_CORE, "%s:~ProcessDataPlugin!", __func__);
48 
49     buffer_ = nullptr;
50 
51     return;
52 }
53 
Start(const uint8_t * configData,uint32_t configSize)54 int ProcessDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
55 {
56     CHECK_NOTNULL(buffer_, RET_FAIL, "%s:buffer_ == null", __func__);
57 
58     CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
59                "%s:parseFromArray failed!", __func__);
60 
61     int ret = COMMON::PluginWriteToHisysevent("process_plugin", "sh", GetCmdArgs(protoConfig_),
62                                               COMMON::ErrorType::RET_SUCC, "success");
63     PROFILER_LOG_INFO(LOG_CORE, "%s: success! hisysevent report process_plugin result:%d", __func__, ret);
64     return RET_SUCC;
65 }
66 
GetCmdArgs(const ProcessConfig & traceConfig)67 std::string ProcessDataPlugin::GetCmdArgs(const ProcessConfig& traceConfig)
68 {
69     std::stringstream args;
70     args << "report_process_tree: " << (traceConfig.report_process_tree() ? "true" : "false") << ", ";
71     args << "report_cpu: " << (traceConfig.report_cpu() ? "true" : "false") << ", ";
72     args << "report_diskio: " << (traceConfig.report_diskio() ? "true" : "false") << ", ";
73     args << "report_pss: " << (traceConfig.report_pss() ? "true" : "false");
74     return args.str();
75 }
76 
ReportOptimize(RandomWriteCtx * randomWrite)77 int ProcessDataPlugin::ReportOptimize(RandomWriteCtx* randomWrite)
78 {
79     ProtoEncoder::ProcessData dataProto(randomWrite);
80     if (protoConfig_.report_process_tree()) {
81         WriteProcesseList(dataProto);
82     }
83 
84     int msgSize = dataProto.Finish();
85     return msgSize;
86 }
87 
Report(uint8_t * data,uint32_t dataSize)88 int ProcessDataPlugin::Report(uint8_t* data, uint32_t dataSize)
89 {
90     ProcessData dataProto;
91     uint32_t length;
92 
93     if (protoConfig_.report_process_tree()) {
94         WriteProcesseList(dataProto);
95     }
96 
97     length = dataProto.ByteSizeLong();
98     if (length > dataSize) {
99         return -length;
100     }
101     if (dataProto.SerializeToArray(data, length) > 0) {
102         return length;
103     }
104     return 0;
105 }
106 
Stop()107 int ProcessDataPlugin::Stop()
108 {
109     pids_.clear();
110     cpuTime_.clear();
111     bootTime_.clear();
112 
113     PROFILER_LOG_INFO(LOG_CORE, "%s:stop success!", __func__);
114     return 0;
115 }
116 
OpenDestDir(const char * dirPath)117 DIR* ProcessDataPlugin::OpenDestDir(const char* dirPath)
118 {
119     DIR* destDir = nullptr;
120 
121     destDir = opendir(dirPath);
122     if (destDir == nullptr) {
123         PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to opendir(%s), errno=%d", __func__, dirPath, errno);
124     }
125 
126     return destDir;
127 }
128 
GetValidPid(DIR * dirp)129 int32_t ProcessDataPlugin::GetValidPid(DIR* dirp)
130 {
131     if (!dirp) {
132         return 0;
133     }
134     while (struct dirent* dirEnt = readdir(dirp)) {
135         if (dirEnt->d_type != DT_DIR) {
136             continue;
137         }
138         if (!COMMON::IsNumeric(std::string(dirEnt->d_name))) {
139             continue;
140         }
141         int32_t pid = atoi(dirEnt->d_name);
142         if (pid) {
143             return pid;
144         }
145     }
146     return 0;
147 }
148 
ReadProcPidFile(int32_t pid,const char * pFileName)149 int32_t ProcessDataPlugin::ReadProcPidFile(int32_t pid, const char* pFileName)
150 {
151     char fileName[PATH_MAX + 1] = {0};
152     char realPath[PATH_MAX + 1] = {0};
153     int fd = -1;
154     ssize_t bytesRead = 0;
155 
156     if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s%d/%s", path_.c_str(), pid, pFileName) < 0) {
157         PROFILER_LOG_ERROR(LOG_CORE, "%s:snprintf_s error", __func__);
158     }
159     if (realpath(fileName, realPath) == nullptr) {
160         PROFILER_LOG_ERROR(LOG_CORE, "%s:realpath failed, errno=%d", __func__, errno);
161         return RET_FAIL;
162     }
163     fd = open(realPath, O_RDONLY | O_CLOEXEC);
164     if (fd == -1) {
165         PROFILER_LOG_INFO(LOG_CORE, "%s:failed to open(%s), errno=%d", __func__, fileName, errno);
166         err_ = errno;
167         return RET_FAIL;
168     }
169     if (buffer_.get() == nullptr) {
170         PROFILER_LOG_INFO(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
171         err_ = RET_NULL_ADDR;
172         close(fd);
173         return RET_FAIL;
174     }
175     bytesRead = read(fd, buffer_.get(), READ_BUFFER_SIZE - 1);
176     if (bytesRead < 0) {
177         close(fd);
178         PROFILER_LOG_INFO(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, fileName, errno);
179         err_ = errno;
180         return RET_FAIL;
181     }
182     buffer_.get()[bytesRead] = '\0';
183     close(fd);
184 
185     return bytesRead;
186 }
187 
BufnCmp(const char * src,int srcLen,const char * key,int keyLen)188 bool ProcessDataPlugin::BufnCmp(const char* src, int srcLen, const char* key, int keyLen)
189 {
190     if (!src || !key || (srcLen < keyLen)) {
191         return false;
192     }
193     for (int i = 0; i < keyLen; i++) {
194         if (*src++ != *key++) {
195             return false;
196         }
197     }
198     return true;
199 }
200 
addPidBySort(int32_t pid)201 bool ProcessDataPlugin::addPidBySort(int32_t pid)
202 {
203     auto pidsEnd = pids_.end();
204     auto it = std::lower_bound(pids_.begin(), pidsEnd, pid);
205     if (it != pidsEnd && *it == pid) {
206         return false;
207     }
208     it = pids_.insert(it, std::move(pid));
209     return true;
210 }
211 
212 template <typename T>
WriteProcess(T & processinfo,const char * pFile,uint32_t fileLen,int32_t pid)213 void ProcessDataPlugin::WriteProcess(T& processinfo, const char* pFile, uint32_t fileLen, int32_t pid)
214 {
215     BufferSplitter totalbuffer(const_cast<const char*>(pFile), fileLen + 1);
216 
217     do {
218         totalbuffer.NextWord(':');
219         if (!totalbuffer.CurWord()) {
220             return;
221         }
222 
223         if (BufnCmp(totalbuffer.CurWord(), totalbuffer.CurWordSize(), "Name", strlen("Name"))) {
224             totalbuffer.NextWord('\n');
225             if (!totalbuffer.CurWord()) {
226                 return;
227             }
228             processinfo.set_name(totalbuffer.CurWord(), totalbuffer.CurWordSize());
229         } else if (BufnCmp(totalbuffer.CurWord(), totalbuffer.CurWordSize(), "Pid", strlen("Pid"))) {
230             totalbuffer.NextWord('\n');
231             if (!totalbuffer.CurWord()) {
232                 return;
233             }
234             char* end = nullptr;
235             int32_t value = static_cast<int32_t>(strtoul(totalbuffer.CurWord(), &end, DEC_BASE));
236             if (value < 0) {
237                 PROFILER_LOG_ERROR(LOG_CORE, "%s:strtoull value failed", __func__);
238             }
239             processinfo.set_pid(value);
240         } else if (BufnCmp(totalbuffer.CurWord(), totalbuffer.CurWordSize(), "PPid", strlen("PPid"))) {
241             totalbuffer.NextWord('\n');
242             if (!totalbuffer.CurWord()) {
243                 return;
244             }
245             char* end = nullptr;
246             int32_t value = static_cast<int32_t>(strtoul(totalbuffer.CurWord(), &end, DEC_BASE));
247             if (value < 0) {
248                 PROFILER_LOG_ERROR(LOG_CORE, "%s:strtoull value failed", __func__);
249             }
250             processinfo.set_ppid(value);
251         } else if (BufnCmp(totalbuffer.CurWord(), totalbuffer.CurWordSize(), "Uid", strlen("Uid"))) {
252             totalbuffer.NextWord('\n');
253             if (!totalbuffer.CurWord()) {
254                 return;
255             }
256             std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
257             curWord = curWord.substr(0, curWord.find(" "));
258             char* end = nullptr;
259             int32_t value = static_cast<int32_t>(strtoul(curWord.c_str(), &end, DEC_BASE));
260             if (value < 0) {
261                 PROFILER_LOG_ERROR(LOG_CORE, "%s:strtoull value failed", __func__);
262             }
263             processinfo.set_uid(value);
264             break;
265         } else {
266             totalbuffer.NextWord('\n');
267             if (!totalbuffer.CurWord()) {
268                 continue;
269             }
270         }
271     } while (totalbuffer.NextLine());
272     // update process name
273     int32_t ret = ReadProcPidFile(pid, "cmdline");
274     if (ret > 0) {
275         processinfo.set_name(reinterpret_cast<char*>(buffer_.get()), strlen(reinterpret_cast<char*>(buffer_.get())));
276     }
277 }
278 
WriteProcessInfo(T & processData,int32_t pid)279 template <typename T> void ProcessDataPlugin::WriteProcessInfo(T& processData, int32_t pid)
280 {
281     int32_t ret = ReadProcPidFile(pid, "status");
282     if (ret == RET_FAIL) {
283         return;
284     }
285     if ((buffer_.get() == nullptr) || (ret == 0)) {
286         return;
287     }
288     auto* processinfo = processData.add_processesinfo();
289     WriteProcess(*processinfo, reinterpret_cast<char*>(buffer_.get()), ret, pid);
290     if (protoConfig_.report_cpu()) {
291         auto* cpuInfo = processinfo->mutable_cpuinfo();
292         std::vector<uint64_t> cpuUsageVec;
293         std::vector<uint64_t> bootTime;
294         WriteCpuUsageData(pid, *cpuInfo);
295         WriteThreadData(pid, *cpuInfo);
296     }
297     if (protoConfig_.report_diskio()) {
298         WriteDiskioData(pid, *processinfo);
299     }
300     if (protoConfig_.report_pss()) {
301         WritePssData(pid, *processinfo);
302     }
303 }
304 
WriteProcesseList(T & processData)305 template <typename T> bool ProcessDataPlugin::WriteProcesseList(T& processData)
306 {
307     DIR* procDir = nullptr;
308 
309     procDir = OpenDestDir(path_.c_str());
310     if (procDir == nullptr) {
311         return false;
312     }
313 
314     pids_.clear();
315     while (int32_t pid = GetValidPid(procDir)) {
316         if (pid <= 0) {
317             closedir(procDir);
318             PROFILER_LOG_WARN(LOG_CORE, "%s: get pid[%d] failed", __func__, pid);
319             return false;
320         }
321         addPidBySort(pid);
322     }
323 
324     for (unsigned int i = 0; i < pids_.size(); i++) {
325         WriteProcessInfo(processData, pids_[i]);
326     }
327 
328     closedir(procDir);
329     return true;
330 }
331 
WriteThreadData(int pid,T & cpuInfo)332 template <typename T> bool ProcessDataPlugin::WriteThreadData(int pid, T& cpuInfo)
333 {
334     DIR* procDir = nullptr;
335     std::string path = path_ + std::to_string(pid) + "/task";
336     procDir = OpenDestDir(path.c_str());
337     if (procDir == nullptr) {
338         return false;
339     }
340 
341     uint32_t i = 0;
342     while (int32_t tid = GetValidPid(procDir)) {
343         if (tid <= 0) {
344             closedir(procDir);
345             PROFILER_LOG_WARN(LOG_CORE, "%s: get pid[%d] failed", __func__, tid);
346             return false;
347         }
348         i++;
349     }
350     cpuInfo.set_thread_sum(i);
351     closedir(procDir);
352     return true;
353 }
354 
GetUserHz()355 int64_t ProcessDataPlugin::GetUserHz()
356 {
357     int64_t hz = -1;
358     int64_t user_hz = sysconf(_SC_CLK_TCK);
359     switch (user_hz) {
360         case CPU_USER_HZ_L:
361             hz = CPU_HZ_H;
362             break;
363         case CPU_USER_HZ_H:
364             hz = 1;
365             break;
366         default:
367             break;
368     }
369     return hz;
370 }
371 
WriteCpuUsageData(int pid,T & cpuInfo)372 template <typename T> bool ProcessDataPlugin::WriteCpuUsageData(int pid, T& cpuInfo)
373 {
374     uint64_t prevCpuTime = 0;
375     uint64_t cpuTime = 0;
376     uint64_t prevBootTime = 0;
377     uint64_t bootTime = 0;
378     double usage = 0.0;
379     ReadCpuUsage(pid, cpuTime);
380     ReadBootTime(pid, bootTime);
381     if (cpuTime_.find(pid) != cpuTime_.end()) {
382         prevCpuTime = cpuTime_[pid];
383     }
384     if (bootTime_.find(pid) != bootTime_.end()) {
385         prevBootTime = bootTime_[pid];
386     }
387     if (bootTime - prevBootTime == 0 || bootTime == 0) {
388         return false;
389     }
390     if (cpuTime < prevCpuTime) {
391         return false;
392     }
393     if (prevCpuTime == 0) {
394         usage = static_cast<double>(cpuTime) / (bootTime);
395     } else {
396         usage = static_cast<double>(cpuTime - prevCpuTime) / (bootTime - prevBootTime);
397     }
398 
399     if (usage > 0) {
400         cpuInfo.set_cpu_usage(usage * PERCENT);
401     }
402     cpuInfo.set_cpu_time_ms(cpuTime);
403     cpuTime_[pid] = cpuTime;
404     bootTime_[pid] = bootTime;
405     return true;
406 }
407 
ReadBootTime(int pid,uint64_t & bootTime)408 bool ProcessDataPlugin::ReadBootTime(int pid, uint64_t& bootTime)
409 {
410     std::string path = path_ + "stat";
411     std::ifstream input(path, std::ios::in);
412     CHECK_TRUE(!input.fail(), false, "%s open %s failed, errno = %d", __func__, path.c_str(), errno);
413     do {
414         if (!input.good()) {
415             return false;
416         }
417         std::string line;
418         getline(input, line);
419 
420         auto pos = line.find("cpu ");
421         if (pos != std::string::npos) {
422             line += '\n';
423             GetBootData(line, bootTime);
424         }
425     } while (0);
426     input.close();
427 
428     return true;
429 }
430 
GetBootData(const std::string & line,uint64_t & bootTime)431 uint32_t ProcessDataPlugin::GetBootData(const std::string& line, uint64_t& bootTime)
432 {
433     uint64_t num;
434     uint32_t count = 0;
435     char* end = nullptr;
436     char* pTmp = const_cast<char*>(line.c_str());
437     constexpr uint32_t cntVec = 8;
438 
439     std::vector<uint64_t> bootTimeVec;
440     bootTime = 0;
441     while (pTmp != nullptr && *pTmp != '\n') {
442         CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
443         num = strtoull(pTmp, &end, DEC_BASE);
444         CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
445         bootTimeVec.push_back(num);
446         bootTime += num;
447         pTmp = end;
448         if (++count >= cntVec) {
449             break;
450         }
451     }
452     bootTime = bootTime * (uint64_t)GetUserHz();
453     return count;
454 }
455 
ReadCpuUsage(int pid,uint64_t & cpuTime)456 bool ProcessDataPlugin::ReadCpuUsage(int pid, uint64_t& cpuTime)
457 {
458     std::string path = path_ + std::to_string(pid) + "/stat";
459     std::ifstream input(path, std::ios::in);
460     CHECK_TRUE(!input.fail(), false, "%s open %s failed, errno = %d", __func__, path.c_str(), errno);
461     do {
462         if (!input.good()) {
463             return false;
464         }
465         std::string line;
466         getline(input, line);
467         line += '\n';
468         GetCpuUsageData(line, cpuTime);
469     } while (0);
470     input.close();
471 
472     return true;
473 }
474 
GetCpuUsageData(const std::string & line,uint64_t & cpuTime)475 uint32_t ProcessDataPlugin::GetCpuUsageData(const std::string& line, uint64_t& cpuTime)
476 {
477     uint64_t num;
478     uint32_t count = 0;
479     char* end = nullptr;
480     char* pTmp = const_cast<char*>(line.c_str());
481     int i = 0;
482     constexpr uint32_t cntVec = 4;
483 
484     while (FindFirstSpace(&pTmp)) {
485         pTmp++;
486         if (++i >= STAT_COUNT) {
487             break;
488         }
489     }
490     std::vector<uint64_t> cpuUsageVec;
491     cpuTime = 0;
492     while (pTmp != nullptr && *pTmp != '\n') {
493         CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
494         num = strtoull(pTmp, &end, DEC_BASE);
495         cpuUsageVec.push_back(num);
496         cpuTime += num;
497         pTmp = end;
498         if (++count >= cntVec) {
499             break;
500         }
501     }
502     cpuTime = cpuTime * (uint64_t)GetUserHz();
503     return count;
504 }
505 
WriteDiskioData(int pid,T & processinfo)506 template <typename T> bool ProcessDataPlugin::WriteDiskioData(int pid, T& processinfo)
507 {
508     std::string path = path_ + std::to_string(pid) + "/io";
509     std::ifstream input(path, std::ios::in);
510     if (input.fail()) {
511         return false;
512     }
513 
514     auto* diskInfo = processinfo.mutable_diskinfo();
515     do {
516         if (!input.good()) {
517             return false;
518         }
519         std::string line;
520         getline(input, line);
521         line += '\n';
522         GetDiskioData(line, *diskInfo);
523     } while (!input.eof());
524     input.close();
525 
526     return true;
527 }
528 
GetDiskioData(std::string & line,T & diskioInfo)529 template <typename T> bool ProcessDataPlugin::GetDiskioData(std::string& line, T& diskioInfo)
530 {
531     char* pTmp = const_cast<char*>(line.c_str());
532     CHECK_NOTNULL(pTmp, false, "param invalid!");
533 
534     uint64_t num;
535     if (!std::strncmp(pTmp, "rchar:", strlen("rchar:"))) {
536         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get rchar failed", __func__);
537         diskioInfo.set_rchar(num);
538     } else if (!std::strncmp(pTmp, "wchar:", strlen("wchar:"))) {
539         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get wchar failed", __func__);
540         diskioInfo.set_wchar(num);
541     } else if (!std::strncmp(pTmp, "syscr:", strlen("syscr:"))) {
542         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get syscr failed", __func__);
543         diskioInfo.set_syscr(num);
544     } else if (!std::strncmp(pTmp, "syscw:", strlen("syscw:"))) {
545         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get syscw failed", __func__);
546         diskioInfo.set_syscw(num);
547     } else if (!std::strncmp(pTmp, "read_bytes:", strlen("read_bytes:"))) {
548         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get read_bytes failed", __func__);
549         diskioInfo.set_rbytes(num);
550     } else if (!std::strncmp(pTmp, "write_bytes:", strlen("write_bytes:"))) {
551         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get write_bytes failed", __func__);
552         diskioInfo.set_wbytes(num);
553     } else if (!std::strncmp(pTmp, "cancelled_write_bytes:", strlen("cancelled_write_bytes:"))) {
554         CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: get cancelled_write_bytes failed", __func__);
555         diskioInfo.set_cancelled_wbytes(num);
556     }
557 
558     return true;
559 }
560 
FindFirstSpace(char ** p)561 bool ProcessDataPlugin::FindFirstSpace(char** p)
562 {
563     CHECK_NOTNULL(*p, false, "ProcessDataPlugin:%s", __func__);
564     while (**p != ' ') {
565         if (**p == '\0' || **p == '\n') {
566             return false;
567         }
568         (*p)++;
569     }
570     return true;
571 }
572 
FindFirstNum(char ** p)573 bool ProcessDataPlugin::FindFirstNum(char** p)
574 {
575     CHECK_NOTNULL(*p, false, "ProcessDataPlugin:%s", __func__);
576     while (**p > '9' || **p < '0') {
577         if (**p == '\0' || **p == '\n') {
578             return false;
579         }
580         (*p)++;
581     }
582     return true;
583 }
584 
GetValidValue(char * p,uint64_t & num)585 bool ProcessDataPlugin::GetValidValue(char* p, uint64_t& num)
586 {
587     char* end = nullptr;
588     CHECK_TRUE(FindFirstNum(&p), false, "%s: FindFirstNum failed", __func__);
589     num = strtoull(p, &end, DEC_BASE);
590     CHECK_TRUE(num >= 0, false, "%s:strtoull failed", __func__);
591     return true;
592 }
593 
594 // read /proc/pid/smaps_rollup
WritePssData(int pid,T & processInfo)595 template <typename T> bool ProcessDataPlugin::WritePssData(int pid, T& processInfo)
596 {
597     std::string path = path_ + std::to_string(pid) + "/smaps_rollup";
598     std::ifstream input(path, std::ios::in);
599 
600     // Not capturing ENOENT (file does not exist) errors, it is common for node smaps_rollup files to be unreadable.
601     CHECK_TRUE(!input.fail(), false, "%s open %s failed, errno = %d", __func__, path.c_str(), errno);
602 
603     auto* pssInfo = processInfo.mutable_pssinfo();
604     do {
605         if (!input.good()) {
606             return false;
607         }
608         std::string line;
609         getline(input, line);
610         line += '\n';
611         std::string::size_type pos = 0u;
612         if (line.find("Pss:", pos) != std::string::npos) {
613             char* pTmp = const_cast<char*>(line.c_str());
614             uint64_t num;
615             CHECK_TRUE(GetValidValue(pTmp, num), false, "%s: FindFirstNum failed", __func__);
616             pssInfo->set_pss_info(num);
617             return true;
618         }
619     } while (!input.eof());
620     input.close();
621 
622     return false;
623 }
624