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}