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