106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci 1606f6ba60Sopenharmony_ci#include "diskio_data_plugin.h" 1706f6ba60Sopenharmony_ci 1806f6ba60Sopenharmony_ci#include <ctime> 1906f6ba60Sopenharmony_ci 2006f6ba60Sopenharmony_ci#include "buffer_splitter.h" 2106f6ba60Sopenharmony_ci#include "diskio_plugin_result.pbencoder.h" 2206f6ba60Sopenharmony_ci 2306f6ba60Sopenharmony_cinamespace { 2406f6ba60Sopenharmony_ciusing namespace OHOS::Developtools::Profiler; 2506f6ba60Sopenharmony_ciconstexpr size_t READ_BUFFER_SIZE = 1024 * 16; 2606f6ba60Sopenharmony_ci} // namespace 2706f6ba60Sopenharmony_ci 2806f6ba60Sopenharmony_ciDiskioDataPlugin::DiskioDataPlugin() 2906f6ba60Sopenharmony_ci{ 3006f6ba60Sopenharmony_ci ioEntry_ = nullptr; 3106f6ba60Sopenharmony_ci buffer_ = nullptr; 3206f6ba60Sopenharmony_ci path_ = "/proc/vmstat"; 3306f6ba60Sopenharmony_ci err_ = -1; 3406f6ba60Sopenharmony_ci prevRdSectorsKb_ = 0; 3506f6ba60Sopenharmony_ci prevWrSectorsKb_ = 0; 3606f6ba60Sopenharmony_ci prevTimestamp_.tv_sec = 0; 3706f6ba60Sopenharmony_ci prevTimestamp_.tv_nsec = 0; 3806f6ba60Sopenharmony_ci} 3906f6ba60Sopenharmony_ci 4006f6ba60Sopenharmony_ciDiskioDataPlugin::~DiskioDataPlugin() 4106f6ba60Sopenharmony_ci{ 4206f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:~DiskioDataPlugin!", __func__); 4306f6ba60Sopenharmony_ci if (buffer_ != nullptr) { 4406f6ba60Sopenharmony_ci free(buffer_); 4506f6ba60Sopenharmony_ci buffer_ = nullptr; 4606f6ba60Sopenharmony_ci } 4706f6ba60Sopenharmony_ci} 4806f6ba60Sopenharmony_ci 4906f6ba60Sopenharmony_ciint DiskioDataPlugin::Start(const uint8_t* configData, uint32_t configSize) 5006f6ba60Sopenharmony_ci{ 5106f6ba60Sopenharmony_ci buffer_ = malloc(READ_BUFFER_SIZE); 5206f6ba60Sopenharmony_ci CHECK_NOTNULL(buffer_, RET_FAIL, "%s:malloc buffer_ failed!", __func__); 5306f6ba60Sopenharmony_ci 5406f6ba60Sopenharmony_ci CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL, 5506f6ba60Sopenharmony_ci "%s:parseFromArray failed!", __func__); 5606f6ba60Sopenharmony_ci 5706f6ba60Sopenharmony_ci if (protoConfig_.report_io_stats()) { 5806f6ba60Sopenharmony_ci ioEntry_ = std::make_shared<IoStats>(protoConfig_.report_io_stats()); 5906f6ba60Sopenharmony_ci } 6006f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:start success!", __func__); 6106f6ba60Sopenharmony_ci return RET_SUCC; 6206f6ba60Sopenharmony_ci} 6306f6ba60Sopenharmony_ci 6406f6ba60Sopenharmony_ciint DiskioDataPlugin::ReportOptimize(RandomWriteCtx* randomWrite) 6506f6ba60Sopenharmony_ci{ 6606f6ba60Sopenharmony_ci ProtoEncoder::DiskioData dataProto(randomWrite); 6706f6ba60Sopenharmony_ci WriteDiskioData(dataProto); 6806f6ba60Sopenharmony_ci 6906f6ba60Sopenharmony_ci if (protoConfig_.report_io_stats() && ioEntry_ != nullptr) { 7006f6ba60Sopenharmony_ci ioEntry_->GetIoData(); 7106f6ba60Sopenharmony_ci auto* statsData = dataProto.mutable_statsdata(); 7206f6ba60Sopenharmony_ci ioEntry_->PutPluginStatsData(*statsData); 7306f6ba60Sopenharmony_ci } 7406f6ba60Sopenharmony_ci 7506f6ba60Sopenharmony_ci int32_t msgSize = dataProto.Finish(); 7606f6ba60Sopenharmony_ci return static_cast<int>(msgSize); 7706f6ba60Sopenharmony_ci} 7806f6ba60Sopenharmony_ci 7906f6ba60Sopenharmony_ciint DiskioDataPlugin::Report(uint8_t* data, uint32_t dataSize) 8006f6ba60Sopenharmony_ci{ 8106f6ba60Sopenharmony_ci DiskioData dataProto; 8206f6ba60Sopenharmony_ci uint32_t length; 8306f6ba60Sopenharmony_ci 8406f6ba60Sopenharmony_ci WriteDiskioData(dataProto); 8506f6ba60Sopenharmony_ci 8606f6ba60Sopenharmony_ci if (protoConfig_.report_io_stats() && ioEntry_ != nullptr) { 8706f6ba60Sopenharmony_ci ioEntry_->GetIoData(); 8806f6ba60Sopenharmony_ci auto* statsData = dataProto.mutable_statsdata(); 8906f6ba60Sopenharmony_ci ioEntry_->PutPluginStatsData(*statsData); 9006f6ba60Sopenharmony_ci } 9106f6ba60Sopenharmony_ci 9206f6ba60Sopenharmony_ci length = dataProto.ByteSizeLong(); 9306f6ba60Sopenharmony_ci if (length > dataSize) { 9406f6ba60Sopenharmony_ci return -length; 9506f6ba60Sopenharmony_ci } 9606f6ba60Sopenharmony_ci if (dataProto.SerializeToArray(data, length) > 0) { 9706f6ba60Sopenharmony_ci return length; 9806f6ba60Sopenharmony_ci } 9906f6ba60Sopenharmony_ci return 0; 10006f6ba60Sopenharmony_ci} 10106f6ba60Sopenharmony_ci 10206f6ba60Sopenharmony_ciint DiskioDataPlugin::Stop() 10306f6ba60Sopenharmony_ci{ 10406f6ba60Sopenharmony_ci if (buffer_ != nullptr) { 10506f6ba60Sopenharmony_ci free(buffer_); 10606f6ba60Sopenharmony_ci buffer_ = nullptr; 10706f6ba60Sopenharmony_ci } 10806f6ba60Sopenharmony_ci if (ioEntry_ != nullptr) { 10906f6ba60Sopenharmony_ci ioEntry_.reset(); 11006f6ba60Sopenharmony_ci ioEntry_ = nullptr; 11106f6ba60Sopenharmony_ci } 11206f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:plugin:stop success!", __func__); 11306f6ba60Sopenharmony_ci return 0; 11406f6ba60Sopenharmony_ci} 11506f6ba60Sopenharmony_ci 11606f6ba60Sopenharmony_ciint32_t DiskioDataPlugin::ReadFile(std::string& fileName) 11706f6ba60Sopenharmony_ci{ 11806f6ba60Sopenharmony_ci int fd = -1; 11906f6ba60Sopenharmony_ci ssize_t bytesRead = 0; 12006f6ba60Sopenharmony_ci char realPath[PATH_MAX + 1] = {0}; 12106f6ba60Sopenharmony_ci CHECK_TRUE((fileName.length() < PATH_MAX) && (realpath(fileName.c_str(), realPath) != nullptr), RET_FAIL, 12206f6ba60Sopenharmony_ci "%s:path is invalid: %s, errno=%d", __func__, fileName.c_str(), errno); 12306f6ba60Sopenharmony_ci fd = open(realPath, O_RDONLY | O_CLOEXEC); 12406f6ba60Sopenharmony_ci if (fd == -1) { 12506f6ba60Sopenharmony_ci PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno=%d", __func__, fileName.c_str(), errno); 12606f6ba60Sopenharmony_ci err_ = errno; 12706f6ba60Sopenharmony_ci return RET_FAIL; 12806f6ba60Sopenharmony_ci } 12906f6ba60Sopenharmony_ci if (buffer_ == nullptr) { 13006f6ba60Sopenharmony_ci PROFILER_LOG_ERROR(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__); 13106f6ba60Sopenharmony_ci err_ = RET_NULL_ADDR; 13206f6ba60Sopenharmony_ci close(fd); 13306f6ba60Sopenharmony_ci return RET_FAIL; 13406f6ba60Sopenharmony_ci } 13506f6ba60Sopenharmony_ci bytesRead = read(fd, buffer_, READ_BUFFER_SIZE - 1); 13606f6ba60Sopenharmony_ci if (bytesRead <= 0) { 13706f6ba60Sopenharmony_ci close(fd); 13806f6ba60Sopenharmony_ci PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, fileName.c_str(), errno); 13906f6ba60Sopenharmony_ci err_ = errno; 14006f6ba60Sopenharmony_ci return RET_FAIL; 14106f6ba60Sopenharmony_ci } 14206f6ba60Sopenharmony_ci close(fd); 14306f6ba60Sopenharmony_ci 14406f6ba60Sopenharmony_ci return bytesRead; 14506f6ba60Sopenharmony_ci} 14606f6ba60Sopenharmony_ci 14706f6ba60Sopenharmony_citemplate <typename T> void DiskioDataPlugin::SetTimestamp(T& diskioData) 14806f6ba60Sopenharmony_ci{ 14906f6ba60Sopenharmony_ci auto* prevTimestamp = diskioData.mutable_prev_timestamp(); 15006f6ba60Sopenharmony_ci prevTimestamp->set_tv_sec(prevTimestamp_.tv_sec); 15106f6ba60Sopenharmony_ci prevTimestamp->set_tv_nsec(prevTimestamp_.tv_nsec); 15206f6ba60Sopenharmony_ci 15306f6ba60Sopenharmony_ci timespec time; 15406f6ba60Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &time); 15506f6ba60Sopenharmony_ci auto* timestamp = diskioData.mutable_timestamp(); 15606f6ba60Sopenharmony_ci timestamp->set_tv_sec(time.tv_sec); 15706f6ba60Sopenharmony_ci timestamp->set_tv_nsec(time.tv_nsec); 15806f6ba60Sopenharmony_ci 15906f6ba60Sopenharmony_ci prevTimestamp_.tv_sec = time.tv_sec; 16006f6ba60Sopenharmony_ci prevTimestamp_.tv_nsec = time.tv_nsec; 16106f6ba60Sopenharmony_ci} 16206f6ba60Sopenharmony_ci 16306f6ba60Sopenharmony_citemplate <typename T> void DiskioDataPlugin::SetDiskioData(T& diskioData, const char* pFile, uint32_t fileLen) 16406f6ba60Sopenharmony_ci{ 16506f6ba60Sopenharmony_ci BufferSplitter totalbuffer(const_cast<char*>(pFile), fileLen + 1); 16606f6ba60Sopenharmony_ci int64_t rd_sectors_kb = 0; 16706f6ba60Sopenharmony_ci int64_t wr_sectors_kb = 0; 16806f6ba60Sopenharmony_ci 16906f6ba60Sopenharmony_ci do { 17006f6ba60Sopenharmony_ci totalbuffer.NextWord(' '); 17106f6ba60Sopenharmony_ci std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 17206f6ba60Sopenharmony_ci if (strcmp(curWord.c_str(), "pgpgin") == 0) { 17306f6ba60Sopenharmony_ci if (!totalbuffer.NextWord('\n')) { 17406f6ba60Sopenharmony_ci PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to get pgpgin, CurWord() = %s", 17506f6ba60Sopenharmony_ci __func__, totalbuffer.CurWord()); 17606f6ba60Sopenharmony_ci break; 17706f6ba60Sopenharmony_ci } 17806f6ba60Sopenharmony_ci curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 17906f6ba60Sopenharmony_ci rd_sectors_kb = atoi(curWord.c_str()); 18006f6ba60Sopenharmony_ci } else if (strcmp(curWord.c_str(), "pgpgout") == 0) { 18106f6ba60Sopenharmony_ci if (!totalbuffer.NextWord('\n')) { 18206f6ba60Sopenharmony_ci PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to get pgpgout, CurWord() = %s", 18306f6ba60Sopenharmony_ci __func__, totalbuffer.CurWord()); 18406f6ba60Sopenharmony_ci break; 18506f6ba60Sopenharmony_ci } 18606f6ba60Sopenharmony_ci curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 18706f6ba60Sopenharmony_ci wr_sectors_kb = atoi(curWord.c_str()); 18806f6ba60Sopenharmony_ci } 18906f6ba60Sopenharmony_ci } while (totalbuffer.NextLine()); 19006f6ba60Sopenharmony_ci 19106f6ba60Sopenharmony_ci // 前一次系统从磁盘调入的总KB数rd1,通过时间间隔t内KB增量计算磁盘读取速率(rd2-rd1)/t 19206f6ba60Sopenharmony_ci diskioData.set_prev_rd_sectors_kb(prevRdSectorsKb_); 19306f6ba60Sopenharmony_ci // 前一次系统调出到磁盘的总KB数wr1,通过时间间隔t内KB增量计算磁盘写入速率(wr2-wr1)/t 19406f6ba60Sopenharmony_ci diskioData.set_prev_wr_sectors_kb(prevWrSectorsKb_); 19506f6ba60Sopenharmony_ci diskioData.set_rd_sectors_kb(rd_sectors_kb); // 当前系统从磁盘调入的总KB数rd2 19606f6ba60Sopenharmony_ci diskioData.set_wr_sectors_kb(wr_sectors_kb); // 当前系统调出到磁盘的总KB数wr2 19706f6ba60Sopenharmony_ci prevRdSectorsKb_ = rd_sectors_kb; 19806f6ba60Sopenharmony_ci prevWrSectorsKb_ = wr_sectors_kb; 19906f6ba60Sopenharmony_ci SetTimestamp(diskioData); // 设置前一次时间戳和当前时间戳,以便计算两次获取数据的时间间隔t 20006f6ba60Sopenharmony_ci} 20106f6ba60Sopenharmony_ci 20206f6ba60Sopenharmony_citemplate <typename T> void DiskioDataPlugin::WriteDiskioData(T& diskioData) 20306f6ba60Sopenharmony_ci{ 20406f6ba60Sopenharmony_ci int32_t ret = ReadFile(path_); 20506f6ba60Sopenharmony_ci if (ret == RET_FAIL) { 20606f6ba60Sopenharmony_ci return; 20706f6ba60Sopenharmony_ci } 20806f6ba60Sopenharmony_ci if ((buffer_ == nullptr) || (ret == 0)) { 20906f6ba60Sopenharmony_ci return; 21006f6ba60Sopenharmony_ci } 21106f6ba60Sopenharmony_ci 21206f6ba60Sopenharmony_ci SetDiskioData(diskioData, reinterpret_cast<char*>(buffer_), ret); 21306f6ba60Sopenharmony_ci}