• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 "io_collector_impl.h"
17 
18 #include <regex>
19 
20 #include <fcntl.h>
21 #include <securec.h>
22 #include <string_ex.h>
23 #include <unistd.h>
24 
25 #include "common_util.h"
26 #include "common_utils.h"
27 #include "file_util.h"
28 #include "io_calculator.h"
29 #include "io_decorator.h"
30 #include "hiview_logger.h"
31 #include "process_status.h"
32 #include "string_util.h"
33 #include "time_util.h"
34 
35 using namespace OHOS::HiviewDFX::UCollect;
36 
37 namespace OHOS {
38 namespace HiviewDFX {
39 namespace UCollectUtil {
40 namespace {
41 DEFINE_LOG_TAG("UCollectUtil-IoCollector");
42 constexpr int DISK_STATS_SIZE = 12;
43 constexpr int DISK_STATS_PERIOD = 2;
44 constexpr int PROC_IO_STATS_PERIOD = 2;
45 constexpr int EMMC_INFO_SIZE_RATIO = 2 * 1024 * 1024;
46 constexpr int MAX_FILE_NUM = 10;
47 constexpr char MMC[] = "mmc";
48 constexpr char EXPORT_FILE_SUFFIX[] = ".txt";
49 constexpr char EXPORT_FILE_REGEX[] = "[0-9]{14}(.*)";
50 constexpr char UNDERLINE[] = "_";
51 constexpr char RAW_DISK_STATS_FILE_PREFIX[] = "proc_diskstats_";
52 constexpr char DISK_STATS_FILE_PREFIX[] = "proc_diskstats_statistics_";
53 constexpr char EMMC_INFO_FILE_PREFIX[] = "emmc_info_";
54 constexpr char PROC_IO_STATS_FILE_PREFIX[] = "proc_io_stats_";
55 constexpr char SYS_IO_STATS_FILE_PREFIX[] = "sys_io_stats_";
56 constexpr char PROC_DISKSTATS[] = "/proc/diskstats";
57 constexpr char COLLECTION_IO_PATH[] = "/data/log/hiview/unified_collection/io/";
58 }
59 
Create()60 std::shared_ptr<IoCollector> IoCollector::Create()
61 {
62     static std::shared_ptr<IoCollector> instance_ = std::make_shared<IoDecorator>(std::make_shared<IoCollectorImpl>());
63     return instance_;
64 }
65 
IoCollectorImpl()66 IoCollectorImpl::IoCollectorImpl()
67 {
68     HIVIEW_LOGI("init collect data.");
69     InitDiskData();
70     InitProcIoData();
71 }
72 
InitDiskData()73 void IoCollectorImpl::InitDiskData()
74 {
75     std::unique_lock<std::mutex> lockDisk(collectDiskMutex_);
76     preCollectDiskTime_ = TimeUtil::GetMilliseconds();
77     CalculateDiskStats(0, true);
78 }
79 
InitProcIoData()80 void IoCollectorImpl::InitProcIoData()
81 {
82     std::unique_lock<std::mutex> lockProcIo(collectProcIoMutex_);
83     currCollectProcIoTime_ = TimeUtil::GetMilliseconds();
84     preCollectProcIoTime_ = currCollectProcIoTime_;
85     CalculateAllProcIoStats(0, true);
86 }
87 
CollectProcessIo(int32_t pid)88 CollectResult<ProcessIo> IoCollectorImpl::CollectProcessIo(int32_t pid)
89 {
90     CollectResult<ProcessIo> result;
91     std::string filename = PROC + std::to_string(pid) + IO;
92     std::string content;
93     FileUtil::LoadStringFromFile(filename, content);
94     std::vector<std::string> vec;
95     OHOS::SplitStr(content, "\n", vec);
96     ProcessIo& processIO = result.data;
97     processIO.pid = pid;
98     processIO.name = CommonUtils::GetProcNameByPid(pid);
99     std::string type;
100     int64_t value = 0;
101     for (const std::string &str : vec) {
102         if (CommonUtil::ParseTypeAndValue(str, type, value)) {
103             if (type == "rchar") {
104                 processIO.rchar = static_cast<uint64_t>(value);
105             } else if (type == "wchar") {
106                 processIO.wchar = static_cast<uint64_t>(value);
107             } else if (type == "syscr") {
108                 processIO.syscr = static_cast<uint64_t>(value);
109             } else if (type == "syscw") {
110                 processIO.syscw = static_cast<uint64_t>(value);
111             } else if (type == "read_bytes") {
112                 processIO.readBytes = static_cast<uint64_t>(value);
113             } else if (type == "cancelled_write_bytes") {
114                 processIO.cancelledWriteBytes = static_cast<uint64_t>(value);
115             } else if (type == "write_bytes") {
116                 processIO.writeBytes = static_cast<uint64_t>(value);
117             }
118         }
119     }
120     result.retCode = UcError::SUCCESS;
121     return result;
122 }
123 
GetDirRegexFiles(const std::string & path,const std::string & pattern,std::vector<std::string> & files)124 static void GetDirRegexFiles(const std::string& path, const std::string& pattern,
125     std::vector<std::string>& files)
126 {
127     DIR* dir = opendir(path.c_str());
128     if (dir == nullptr) {
129         HIVIEW_LOGE("failed to open dir=%{public}s", path.c_str());
130         return;
131     }
132     std::regex reg = std::regex(pattern);
133     while (true) {
134         struct dirent* ptr = readdir(dir);
135         if (ptr == nullptr) {
136             break;
137         }
138         if (ptr->d_type == DT_REG) {
139             if (regex_match(ptr->d_name, reg)) {
140                 files.push_back(FileUtil::IncludeTrailingPathDelimiter(path) + std::string(ptr->d_name));
141             }
142         }
143     }
144     closedir(dir);
145     std::sort(files.begin(), files.end());
146 }
147 
CreateExportFileName(const std::string & filePrefix)148 std::string IoCollectorImpl::CreateExportFileName(const std::string& filePrefix)
149 {
150     std::unique_lock<std::mutex> lock(exportFileMutex_);
151     if (!FileUtil::IsDirectory(COLLECTION_IO_PATH) && !FileUtil::ForceCreateDirectory(COLLECTION_IO_PATH)) {
152         HIVIEW_LOGE("failed to create dir=%{public}s", COLLECTION_IO_PATH);
153         return "";
154     }
155 
156     std::vector<std::string> files;
157     GetDirRegexFiles(COLLECTION_IO_PATH, filePrefix + EXPORT_FILE_REGEX, files);
158     if (files.size() >= MAX_FILE_NUM) {
159         for (size_t index = 0; index <= files.size() - MAX_FILE_NUM; ++index) {
160             HIVIEW_LOGI("remove file=%{public}s", files[index].c_str());
161             (void)FileUtil::RemoveFile(files[index]);
162         }
163     }
164 
165     uint64_t fileTime = TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC;
166     std::string timeFormat = TimeUtil::TimestampFormatToDate(fileTime, "%Y%m%d%H%M%S");
167     std::string fileName;
168     fileName.append(COLLECTION_IO_PATH).append(filePrefix).append(timeFormat);
169     if (!files.empty()) {
170         auto startPos = files.back().find(timeFormat);
171         if (startPos != std::string::npos) {
172             // yyyymmddHHMMSS_1.txt
173             int fileNameNum = CommonUtil::GetFileNameNum(files.back().substr(startPos), EXPORT_FILE_SUFFIX);
174             fileName.append(UNDERLINE).append(std::to_string(++fileNameNum));
175         }
176     }
177     fileName.append(EXPORT_FILE_SUFFIX);
178     (void)FileUtil::CreateFile(fileName);
179     HIVIEW_LOGI("create file=%{public}s", fileName.c_str());
180     return fileName;
181 }
182 
CollectRawDiskStats()183 CollectResult<std::string> IoCollectorImpl::CollectRawDiskStats()
184 {
185     CollectResult<std::string> result;
186     result.retCode = UcError::UNSUPPORT;
187 
188     std::string fileName = CreateExportFileName(RAW_DISK_STATS_FILE_PREFIX);
189     if (fileName.empty()) {
190         return result;
191     }
192     int ret = FileUtil::CopyFile(PROC_DISKSTATS, fileName);
193     if (ret != 0) {
194         HIVIEW_LOGE("copy /proc/diskstats to file=%{public}s failed.", fileName.c_str());
195         return result;
196     }
197 
198     result.data = fileName;
199     result.retCode = UcError::SUCCESS;
200     return result;
201 }
202 
CollectDiskStats(DiskStatsFilter filter,bool isUpdate)203 CollectResult<std::vector<DiskStats>> IoCollectorImpl::CollectDiskStats(DiskStatsFilter filter, bool isUpdate)
204 {
205     CollectResult<std::vector<DiskStats>> result;
206     GetDiskStats(filter, isUpdate, result.data);
207     HIVIEW_LOGI("collect disk stats size=%{public}zu, isUpdate=%{public}d", result.data.size(), isUpdate);
208     result.retCode = UcError::SUCCESS;
209     return result;
210 }
211 
GetDiskStats(DiskStatsFilter filter,bool isUpdate,std::vector<DiskStats> & diskStats)212 void IoCollectorImpl::GetDiskStats(DiskStatsFilter filter, bool isUpdate, std::vector<DiskStats>& diskStats)
213 {
214     std::unique_lock<std::mutex> lock(collectDiskMutex_);
215     uint64_t currCollectDiskTime = TimeUtil::GetMilliseconds();
216     uint64_t period = (currCollectDiskTime > preCollectDiskTime_) ?
217         ((currCollectDiskTime - preCollectDiskTime_) / TimeUtil::SEC_TO_MILLISEC) : 0;
218     if (period > DISK_STATS_PERIOD) {
219         if (isUpdate) {
220             preCollectDiskTime_ = currCollectDiskTime;
221         }
222         CalculateDiskStats(period, isUpdate);
223     }
224 
225     for (auto it = diskStatsMap_.begin(); it != diskStatsMap_.end();) {
226         if (it->second.collectTime == preCollectDiskTime_) {
227             if (!it->second.stats.deviceName.empty() && !filter(it->second.stats)) {
228                 diskStats.push_back(it->second.stats);
229             }
230             ++it;
231         } else {
232             it = diskStatsMap_.erase(it);
233         }
234     }
235     return;
236 }
237 
CalculateDiskStats(uint64_t period,bool isUpdate)238 void IoCollectorImpl::CalculateDiskStats(uint64_t period, bool isUpdate)
239 {
240     std::string content;
241     if (!FileUtil::LoadStringFromFile(PROC_DISKSTATS, content) || content.empty()) {
242         HIVIEW_LOGE("load file=%{public}s failed.", PROC_DISKSTATS);
243         return;
244     }
245     std::vector<std::string> contents;
246     OHOS::SplitStr(content, "\n", contents);
247     for (const std::string& line : contents) {
248         std::vector<std::string> items;
249         StringUtil::SplitStr(line, " ", items);
250         if (items.size() < DISK_STATS_SIZE) {
251             HIVIEW_LOGE("items num=%{public}zu.", items.size());
252             continue;
253         }
254         std::string deviceName = items[2]; // 2 : index of device name
255         if (deviceName.empty()) {
256             HIVIEW_LOGE("device name empty.");
257             continue;
258         }
259         DiskData currData;
260         currData.operRead = StringUtil::StringToUl(items[4]);    // 4 : index of reads merged
261         currData.sectorRead = StringUtil::StringToUl(items[5]);  // 5 : index of sectors read
262         currData.readTime = StringUtil::StringToUl(items[6]);    // 6 : index of time spent reading (ms)
263         currData.operWrite = StringUtil::StringToUl(items[8]);   // 8 : index of writes merged
264         currData.sectorWrite = StringUtil::StringToUl(items[9]); // 9 : index of sectors written
265         currData.writeTime = StringUtil::StringToUl(items[10]);  // 10 : index of time spent reading (ms)
266         currData.ioWait = StringUtil::StringToUl(items[11]);     // 11 : index of I/Os currently in progress
267 
268         CalculateDeviceDiskStats(currData, deviceName, period);
269         if (isUpdate) {
270             diskStatsMap_[deviceName].collectTime = preCollectDiskTime_;
271             diskStatsMap_[deviceName].preData = currData;
272         }
273     }
274 }
275 
CalculateDeviceDiskStats(const DiskData & currData,const std::string & deviceName,uint64_t period)276 void IoCollectorImpl::CalculateDeviceDiskStats(const DiskData& currData, const std::string& deviceName, uint64_t period)
277 {
278     if (diskStatsMap_.find(deviceName) == diskStatsMap_.end()) {
279         return;
280     }
281 
282     DiskStatsDevice& device = diskStatsMap_[deviceName];
283     DiskData& preData = device.preData;
284     DiskStats& stats = device.stats;
285     stats.deviceName = deviceName;
286     if (period != 0) {
287         stats.sectorReadRate = IoCalculator::PercentValue(preData.sectorRead, currData.sectorRead, period);
288         stats.sectorWriteRate = IoCalculator::PercentValue(preData.sectorWrite, currData.sectorWrite, period);
289         stats.operReadRate = IoCalculator::PercentValue(preData.operRead, currData.operRead, period);
290         stats.operWriteRate = IoCalculator::PercentValue(preData.operWrite, currData.operWrite, period);
291         stats.readTimeRate = IoCalculator::PercentValue(preData.readTime, currData.readTime, period);
292         stats.writeTimeRate = IoCalculator::PercentValue(preData.writeTime, currData.writeTime, period);
293         stats.ioWait = currData.ioWait;
294     }
295 }
296 
ExportDiskStats(DiskStatsFilter filter)297 CollectResult<std::string> IoCollectorImpl::ExportDiskStats(DiskStatsFilter filter)
298 {
299     CollectResult<std::string> result;
300     result.retCode = UcError::UNSUPPORT;
301 
302     std::vector<DiskStats> diskStats;
303     GetDiskStats(filter, false, diskStats);
304     std::sort(diskStats.begin(), diskStats.end(), [](const DiskStats &leftStats, const DiskStats &rightStats) {
305         return leftStats.deviceName < rightStats.deviceName;
306     });
307 
308     std::string fileName = CreateExportFileName(DISK_STATS_FILE_PREFIX);
309     if (fileName.empty()) {
310         return result;
311     }
312     FILE *filePtr = fopen(fileName.c_str(), "w");
313     if (filePtr == nullptr) {
314         HIVIEW_LOGE("create fileName=%{public}s failed.", fileName.c_str());
315         return result;
316     }
317     fprintf(filePtr, "%-13s\t%20s\t%20s\t%20s\t%20s\t%12s\t%12s\t%12s\n", "device", "sectorReadRate/s",
318         "sectorWriteRate/s", "operReadRate/s", "operWriteRate/s", "readTime", "writeTime", "ioWait");
319     for (auto &stats : diskStats) {
320         fprintf(filePtr, "%-13s\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.4f\t%12.4f\t%12" PRIu64 "\n",
321             stats.deviceName.c_str(), stats.sectorReadRate, stats.sectorWriteRate, stats.operReadRate,
322             stats.operWriteRate, stats.readTimeRate, stats.writeTimeRate, stats.ioWait);
323     }
324     fclose(filePtr);
325 
326     result.retCode = UcError::SUCCESS;
327     result.data = fileName;
328     return result;
329 }
330 
ReadEMMCInfo(const std::string & path,std::vector<EMMCInfo> & mmcInfos)331 void IoCollectorImpl::ReadEMMCInfo(const std::string& path, std::vector<EMMCInfo>& mmcInfos)
332 {
333     EMMCInfo mmcInfo;
334     mmcInfo.type = FileUtil::GetFirstLine(path + "/type");
335     if (mmcInfo.type.empty()) {
336         HIVIEW_LOGE("load file=%{public}s/type failed.", path.c_str());
337         return;
338     }
339     mmcInfo.csd = FileUtil::GetFirstLine(path + "/csd");
340     mmcInfo.name = FileUtil::GetFirstLine(path + "/name");
341     if (mmcInfo.name.empty()) {
342         HIVIEW_LOGE("load file=%{public}s/name failed.", path.c_str());
343         return;
344     }
345     mmcInfo.size = IoCalculator::GetEMMCSize(path);
346     if (mmcInfo.size == -1) {
347         return;
348     }
349     mmcInfo.manfid = IoCalculator::GetEMMCManfid(path);
350     if (mmcInfo.manfid.empty()) {
351         return;
352     }
353     mmcInfos.emplace_back(mmcInfo);
354 }
355 
GetEMMCPath(const std::string & path)356 std::string IoCollectorImpl::GetEMMCPath(const std::string& path)
357 {
358     std::string mmcPath;
359     DIR *dir = opendir(path.c_str());
360     if (dir == nullptr) {
361         HIVIEW_LOGE("open dir=%{public}s failed.", path.c_str());
362         return mmcPath;
363     }
364     struct dirent *de = nullptr;
365     while ((de = readdir(dir)) != nullptr) {
366         if ((de->d_type == DT_LNK) || (de->d_type == DT_DIR)) {
367             std::string fileName = std::string(de->d_name);
368             if (fileName.length() <= strlen(MMC)) {
369                 continue;
370             }
371             if (fileName.substr(0, strlen(MMC)) != MMC) {
372                 continue;
373             }
374             if (fileName.find(":") == std::string::npos) {
375                 continue;
376             }
377             // mmc0:0001
378             mmcPath = path + "/" + fileName + "/cid";
379             if (FileUtil::FileExists(mmcPath)) {
380                 mmcPath = path + "/" + fileName;
381             } else {
382                 mmcPath = "";
383             }
384             break;
385         }
386     }
387     closedir(dir);
388     return mmcPath;
389 }
390 
CalculateEMMCInfo(std::vector<EMMCInfo> & mmcInfos)391 void IoCollectorImpl::CalculateEMMCInfo(std::vector<EMMCInfo>& mmcInfos)
392 {
393     const std::string procBootDevice = "/proc/bootdevice";
394     ReadEMMCInfo(procBootDevice, mmcInfos);
395 
396     const std::string mmcHostPath = "/sys/class/mmc_host";
397     DIR *dir = opendir(mmcHostPath.c_str());
398     if (dir == nullptr) {
399         HIVIEW_LOGE("open dir=%{public}s failed.", mmcHostPath.c_str());
400         return;
401     }
402     struct dirent *de = nullptr;
403     while ((de = readdir(dir)) != nullptr) {
404         if ((de->d_type == DT_LNK) || (de->d_type == DT_DIR)) {
405             if ((strlen(de->d_name) <= strlen(MMC)) || (de->d_name[0] != 'm')) {
406                 continue;
407             }
408             // mmc0
409             std::string mmcPath = mmcHostPath + "/" + std::string(de->d_name);
410             mmcPath = GetEMMCPath(mmcPath);
411             if (!mmcPath.empty()) {
412                 ReadEMMCInfo(mmcPath, mmcInfos);
413             }
414         }
415     }
416     closedir(dir);
417 }
418 
CollectEMMCInfo()419 CollectResult<std::vector<EMMCInfo>> IoCollectorImpl::CollectEMMCInfo()
420 {
421     CollectResult<std::vector<EMMCInfo>> result;
422     CalculateEMMCInfo(result.data);
423     HIVIEW_LOGI("collect emmc info size=%{public}zu", result.data.size());
424     result.retCode = UcError::SUCCESS;
425     return result;
426 }
427 
ExportEMMCInfo()428 CollectResult<std::string> IoCollectorImpl::ExportEMMCInfo()
429 {
430     CollectResult<std::string> result;
431     result.retCode = UcError::UNSUPPORT;
432 
433     std::vector<EMMCInfo> mmcInfos;
434     CalculateEMMCInfo(mmcInfos);
435     std::sort(mmcInfos.begin(), mmcInfos.end(), [](const EMMCInfo &leftInfo, const EMMCInfo &rightInfo) {
436         return leftInfo.name < rightInfo.name;
437     });
438 
439     std::string fileName = CreateExportFileName(EMMC_INFO_FILE_PREFIX);
440     if (fileName.empty()) {
441         return result;
442     }
443     FILE *filePtr = fopen(fileName.c_str(), "w");
444     if (filePtr == nullptr) {
445         HIVIEW_LOGE("open file=%{public}s failed.", fileName.c_str());
446         return result;
447     }
448     fprintf(filePtr, "%-15s\t%15s\t%15s\t%15s\t%15s\n", "name", "manfid", "csd", "type", "capacity(GB)");
449     for (auto &mmcInfo : mmcInfos) {
450         fprintf(filePtr, "%-15s\t%-12s\t%-35s\t%-12s\t%12.2f\n", mmcInfo.name.c_str(), mmcInfo.manfid.c_str(),
451             mmcInfo.csd.c_str(), mmcInfo.type.c_str(), static_cast<double>(mmcInfo.size) / EMMC_INFO_SIZE_RATIO);
452     }
453     fclose(filePtr);
454 
455     result.retCode = UcError::SUCCESS;
456     result.data = fileName;
457     return result;
458 }
459 
GetProcIoStats(std::vector<ProcessIoStats> & allProcIoStats,bool isUpdate)460 void IoCollectorImpl::GetProcIoStats(std::vector<ProcessIoStats>& allProcIoStats, bool isUpdate)
461 {
462     std::unique_lock<std::mutex> lock(collectProcIoMutex_);
463     currCollectProcIoTime_ = TimeUtil::GetMilliseconds();
464     uint64_t period = (currCollectProcIoTime_ > preCollectProcIoTime_) ?
465         ((currCollectProcIoTime_ - preCollectProcIoTime_) / TimeUtil::SEC_TO_MILLISEC) : 0;
466     if (period > PROC_IO_STATS_PERIOD) {
467         CalculateAllProcIoStats(period, isUpdate);
468         if (isUpdate) {
469             preCollectProcIoTime_ = currCollectProcIoTime_;
470         }
471     }
472 
473     for (auto it = procIoStatsMap_.begin(); it != procIoStatsMap_.end();) {
474         if (it->second.collectTime == preCollectProcIoTime_) {
475             if (it->second.stats.pid != 0 && !ProcIoStatsFilter(it->second.stats)) {
476                 allProcIoStats.push_back(it->second.stats);
477             }
478             ++it;
479         } else {
480             it = procIoStatsMap_.erase(it);
481         }
482     }
483 }
484 
CalculateAllProcIoStats(uint64_t period,bool isUpdate)485 void IoCollectorImpl::CalculateAllProcIoStats(uint64_t period, bool isUpdate)
486 {
487     DIR *dir = opendir(PROC);
488     if (dir == nullptr) {
489         HIVIEW_LOGE("open dir=%{public}s failed.", PROC);
490         return;
491     }
492 
493     struct dirent *de = nullptr;
494     while ((de = readdir(dir)) != nullptr) {
495         if (de->d_type != DT_DIR) {
496             continue;
497         }
498         int32_t pid = StringUtil::StrToInt(std::string(de->d_name));
499         if (pid <= 0) {
500             continue;
501         }
502         auto collectProcIoResult = CollectProcessIo(pid);
503         if (collectProcIoResult.retCode == UcError::SUCCESS) {
504             CalculateProcIoStats(collectProcIoResult.data, pid, period);
505             if (isUpdate) {
506                 procIoStatsMap_[pid].collectTime = currCollectProcIoTime_;
507                 procIoStatsMap_[pid].preData = collectProcIoResult.data;
508             }
509         }
510     }
511     closedir(dir);
512 }
513 
ProcIoStatsFilter(const ProcessIoStats & stats)514 bool IoCollectorImpl::ProcIoStatsFilter(const ProcessIoStats& stats)
515 {
516     return (stats.rcharRate == 0 && stats.wcharRate == 0 && stats.syscrRate == 0 && stats.syscwRate == 0 &&
517         stats.readBytesRate == 0 && stats.writeBytesRate == 0);
518 }
519 
GetProcStateInCollectionPeriod(int32_t pid)520 int32_t IoCollectorImpl::GetProcStateInCollectionPeriod(int32_t pid)
521 {
522     ProcessState procState = ProcessStatus::GetInstance().GetProcessState(pid);
523     if (procState == FOREGROUND) {
524         return static_cast<int32_t>(FOREGROUND);
525     }
526     uint64_t procForegroundTime = ProcessStatus::GetInstance().GetProcessLastForegroundTime(pid);
527     if (procForegroundTime >= preCollectProcIoTime_) {
528         return static_cast<int32_t>(FOREGROUND);
529     }
530     return static_cast<int32_t>(procState);
531 }
532 
CalculateProcIoStats(const ProcessIo & currData,int32_t pid,uint64_t period)533 void IoCollectorImpl::CalculateProcIoStats(const ProcessIo& currData, int32_t pid, uint64_t period)
534 {
535     if (procIoStatsMap_.find(pid) == procIoStatsMap_.end()) {
536         return;
537     }
538 
539     ProcessIoStatsInfo& statsInfo = procIoStatsMap_[pid];
540     ProcessIo& preData = statsInfo.preData;
541     ProcessIoStats& stats = statsInfo.stats;
542     stats.pid = pid;
543     stats.name = ProcessStatus::GetInstance().GetProcessName(pid);
544     stats.ground = GetProcStateInCollectionPeriod(pid);
545     if (period != 0) {
546         stats.rcharRate = IoCalculator::PercentValue(preData.rchar, currData.rchar, period);
547         stats.wcharRate = IoCalculator::PercentValue(preData.wchar, currData.wchar, period);
548         stats.syscrRate = IoCalculator::PercentValue(preData.syscr, currData.syscr, period);
549         stats.syscwRate = IoCalculator::PercentValue(preData.syscw, currData.syscw, period);
550         stats.readBytesRate = IoCalculator::PercentValue(preData.readBytes, currData.readBytes, period);
551         stats.writeBytesRate = IoCalculator::PercentValue(preData.writeBytes, currData.writeBytes, period);
552     }
553 }
554 
CollectAllProcIoStats(bool isUpdate)555 CollectResult<std::vector<ProcessIoStats>> IoCollectorImpl::CollectAllProcIoStats(bool isUpdate)
556 {
557     CollectResult<std::vector<ProcessIoStats>> result;
558     GetProcIoStats(result.data, isUpdate);
559     HIVIEW_LOGI("collect process io stats size=%{public}zu, isUpdate=%{public}d", result.data.size(), isUpdate);
560     result.retCode = UcError::SUCCESS;
561     return result;
562 }
563 
ExportAllProcIoStats()564 CollectResult<std::string> IoCollectorImpl::ExportAllProcIoStats()
565 {
566     CollectResult<std::string> result;
567     result.retCode = UcError::UNSUPPORT;
568 
569     std::vector<ProcessIoStats> allProcIoStats;
570     GetProcIoStats(allProcIoStats, false);
571     std::sort(allProcIoStats.begin(), allProcIoStats.end(),
572         [](const ProcessIoStats &leftStats, const ProcessIoStats &rightStats) {
573             return leftStats.name < rightStats.name;
574         });
575 
576     std::string fileName = CreateExportFileName(PROC_IO_STATS_FILE_PREFIX);
577     if (fileName.empty()) {
578         return result;
579     }
580     FILE *filePtr = fopen(fileName.c_str(), "w");
581     if (filePtr == nullptr) {
582         HIVIEW_LOGE("open file=%{public}s failed.", fileName.c_str());
583         return result;
584     }
585     fprintf(filePtr, "%-13s\t%12s\t%12s\t%12s\t%12s\t%12s\t%12s\t%20s\t%20s\n", "pid", "pname", "fg/bg",
586         "rchar/s", "wchar/s", "syscr/s", "syscw/s", "readBytes/s", "writeBytes/s");
587     for (auto &procIoStats : allProcIoStats) {
588         fprintf(filePtr, "%-12d\t%12s\t%12d\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\n",
589             procIoStats.pid, procIoStats.name.c_str(), procIoStats.ground, procIoStats.rcharRate, procIoStats.wcharRate,
590             procIoStats.syscrRate, procIoStats.syscwRate, procIoStats.readBytesRate, procIoStats.writeBytesRate);
591     }
592     fclose(filePtr);
593 
594     result.retCode = UcError::SUCCESS;
595     result.data = fileName;
596     return result;
597 }
598 
CollectSysIoStats()599 CollectResult<SysIoStats> IoCollectorImpl::CollectSysIoStats()
600 {
601     CollectResult<SysIoStats> result;
602     std::vector<ProcessIoStats> allProcIoStats;
603     GetProcIoStats(allProcIoStats, false);
604 
605     auto &sysIoStats = result.data;
606     for (auto &procIoStats : allProcIoStats) {
607         sysIoStats.rcharRate += procIoStats.rcharRate;
608         sysIoStats.wcharRate += procIoStats.wcharRate;
609         sysIoStats.syscrRate += procIoStats.syscrRate;
610         sysIoStats.syscwRate += procIoStats.syscwRate;
611         sysIoStats.readBytesRate += procIoStats.readBytesRate;
612         sysIoStats.writeBytesRate += procIoStats.writeBytesRate;
613     }
614     result.retCode = UcError::SUCCESS;
615     return result;
616 }
617 
ExportSysIoStats()618 CollectResult<std::string> IoCollectorImpl::ExportSysIoStats()
619 {
620     CollectResult<std::string> result;
621     result.retCode = UcError::UNSUPPORT;
622     auto collectSysIoStatsResult = CollectSysIoStats();
623     if (collectSysIoStatsResult.retCode != UcError::SUCCESS) {
624         return result;
625     }
626 
627     std::string fileName = CreateExportFileName(SYS_IO_STATS_FILE_PREFIX);
628     if (fileName.empty()) {
629         return result;
630     }
631     FILE *filePtr = fopen(fileName.c_str(), "w");
632     if (filePtr == nullptr) {
633         HIVIEW_LOGE("open file=%{public}s failed.", fileName.c_str());
634         return result;
635     }
636     fprintf(filePtr, "%-12s\t%12s\t%12s\t%12s\t%20s\t%20s\n",
637         "rchar/s", "wchar/s", "syscr/s", "syscw/s", "readBytes/s", "writeBytes/s");
638     auto &sysIoStats = collectSysIoStatsResult.data;
639     fprintf(filePtr, "%-12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\n", sysIoStats.rcharRate, sysIoStats.wcharRate,
640         sysIoStats.syscrRate, sysIoStats.syscwRate, sysIoStats.readBytesRate, sysIoStats.writeBytesRate);
641     fclose(filePtr);
642 
643     result.retCode = UcError::SUCCESS;
644     result.data = fileName;
645     return result;
646 }
647 } // UCollectUtil
648 } // HiViewDFX
649 } // OHOS
650