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