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#include "io_stats.h"
1606f6ba60Sopenharmony_ci#include "securec.h"
1706f6ba60Sopenharmony_ci
1806f6ba60Sopenharmony_ci#include <sys/types.h>
1906f6ba60Sopenharmony_ci#include <sys/stat.h>
2006f6ba60Sopenharmony_ci#include <fcntl.h>
2106f6ba60Sopenharmony_ci#include <unistd.h>
2206f6ba60Sopenharmony_ci
2306f6ba60Sopenharmony_cinamespace {
2406f6ba60Sopenharmony_ciconst int NUM_ONEHUNDRED = 100;
2506f6ba60Sopenharmony_ciconst double NUM_ZERO_POINTZEROONE = 0.01;
2606f6ba60Sopenharmony_ci#if __DEBUG__
2706f6ba60Sopenharmony_ciconst char* SYSTIME_PATH = "/data/local/tmp/systimes";
2806f6ba60Sopenharmony_ciconst char* CPU_PATH = "/data/local/tmp/cpustats";
2906f6ba60Sopenharmony_ciconst char* DISKSTATS_PATH = "/data/local/tmp/diskstats";
3006f6ba60Sopenharmony_ciconst int NUM_SEVEN = 7;
3106f6ba60Sopenharmony_ci#else
3206f6ba60Sopenharmony_ciconst char* SYSTIME_PATH = "/proc/uptime";
3306f6ba60Sopenharmony_ciconst char* CPU_PATH = "/proc/stat";
3406f6ba60Sopenharmony_ciconst char* DISKSTATS_PATH = "/proc/diskstats";
3506f6ba60Sopenharmony_ci#endif // #if __DEBUG__
3606f6ba60Sopenharmony_ciconst int DEC_BASE = 10;
3706f6ba60Sopenharmony_ci} // namespace
3806f6ba60Sopenharmony_ci
3906f6ba60Sopenharmony_ciIoStats::IoStats(DiskioConfig::IoReportType type) : type_(type)
4006f6ba60Sopenharmony_ci{
4106f6ba60Sopenharmony_ci    sysTime_ = GetSystime();
4206f6ba60Sopenharmony_ci}
4306f6ba60Sopenharmony_ci
4406f6ba60Sopenharmony_ciuint64_t IoStats::GetSystime()
4506f6ba60Sopenharmony_ci{
4606f6ba60Sopenharmony_ci    uint64_t systime = 1;
4706f6ba60Sopenharmony_ci    std::ifstream input(SYSTIME_PATH, std::ios::in);
4806f6ba60Sopenharmony_ci    CHECK_TRUE(!input.fail(), systime, "%s:open %s failed, errno = %d", __func__, SYSTIME_PATH, errno);
4906f6ba60Sopenharmony_ci    do {
5006f6ba60Sopenharmony_ci        if (!input.good()) {
5106f6ba60Sopenharmony_ci            return systime;
5206f6ba60Sopenharmony_ci        }
5306f6ba60Sopenharmony_ci        std::string line;
5406f6ba60Sopenharmony_ci        getline(input, line);
5506f6ba60Sopenharmony_ci        line += '\n';
5606f6ba60Sopenharmony_ci
5706f6ba60Sopenharmony_ci        uint64_t nsec, ncent;
5806f6ba60Sopenharmony_ci        if (ParseLineFields(line) > 0) {
5906f6ba60Sopenharmony_ci            nsec = fields_[0];
6006f6ba60Sopenharmony_ci            ncent = fields_[1];
6106f6ba60Sopenharmony_ci            systime = nsec * NUM_ONEHUNDRED + ncent;
6206f6ba60Sopenharmony_ci        }
6306f6ba60Sopenharmony_ci        fields_.clear();
6406f6ba60Sopenharmony_ci    } while (0);
6506f6ba60Sopenharmony_ci    input.close();
6606f6ba60Sopenharmony_ci
6706f6ba60Sopenharmony_ci    return systime;
6806f6ba60Sopenharmony_ci}
6906f6ba60Sopenharmony_ci
7006f6ba60Sopenharmony_cibool IoStats::GetIoData()
7106f6ba60Sopenharmony_ci{
7206f6ba60Sopenharmony_ci    ParseCpuStats();
7306f6ba60Sopenharmony_ci    if (type_ == DiskioConfig::IO_REPORT) {
7406f6ba60Sopenharmony_ci        ParseIoStats();
7506f6ba60Sopenharmony_ci    } else if (type_ == DiskioConfig::IO_REPORT_EX) {
7606f6ba60Sopenharmony_ci        ParseIoStatsEx();
7706f6ba60Sopenharmony_ci    }
7806f6ba60Sopenharmony_ci    return true;
7906f6ba60Sopenharmony_ci}
8006f6ba60Sopenharmony_ci
8106f6ba60Sopenharmony_cibool IoStats::ParseCpuStats()
8206f6ba60Sopenharmony_ci{
8306f6ba60Sopenharmony_ci    std::ifstream input(CPU_PATH, std::ios::in);
8406f6ba60Sopenharmony_ci    CHECK_TRUE(!input.fail(), false, "%s: open %s failed, errno = %d", __func__, CPU_PATH, errno);
8506f6ba60Sopenharmony_ci    do {
8606f6ba60Sopenharmony_ci        if (!input.good()) {
8706f6ba60Sopenharmony_ci            return false;
8806f6ba60Sopenharmony_ci        }
8906f6ba60Sopenharmony_ci        std::string line;
9006f6ba60Sopenharmony_ci        getline(input, line);
9106f6ba60Sopenharmony_ci
9206f6ba60Sopenharmony_ci        auto pos = line.find("cpu");
9306f6ba60Sopenharmony_ci        if (pos != std::string::npos) {
9406f6ba60Sopenharmony_ci            line += '\n';
9506f6ba60Sopenharmony_ci            GetCpuStats(line);
9606f6ba60Sopenharmony_ci        }
9706f6ba60Sopenharmony_ci    } while (!input.eof());
9806f6ba60Sopenharmony_ci    input.close();
9906f6ba60Sopenharmony_ci
10006f6ba60Sopenharmony_ci    return true;
10106f6ba60Sopenharmony_ci}
10206f6ba60Sopenharmony_ci
10306f6ba60Sopenharmony_cibool IoStats::GetCpuStats(std::string& line)
10406f6ba60Sopenharmony_ci{
10506f6ba60Sopenharmony_ci    std::string name;
10606f6ba60Sopenharmony_ci    auto cpuData = std::make_shared<ProcStats>();
10706f6ba60Sopenharmony_ci    CHECK_NOTNULL(cpuData, false, "create ProcStats FAILED!");
10806f6ba60Sopenharmony_ci
10906f6ba60Sopenharmony_ci    if (ParseLineFields(line, name) > 0) {
11006f6ba60Sopenharmony_ci        int index = 0;
11106f6ba60Sopenharmony_ci        cpuData->name_ = name;
11206f6ba60Sopenharmony_ci        cpuData->user_ = fields_[index];
11306f6ba60Sopenharmony_ci        index++;
11406f6ba60Sopenharmony_ci        cpuData->nice_ = fields_[index];
11506f6ba60Sopenharmony_ci        index++;
11606f6ba60Sopenharmony_ci        cpuData->system_ = fields_[index];
11706f6ba60Sopenharmony_ci        index++;
11806f6ba60Sopenharmony_ci        cpuData->idle_ = fields_[index];
11906f6ba60Sopenharmony_ci        index++;
12006f6ba60Sopenharmony_ci        cpuData->iowait_ = fields_[index];
12106f6ba60Sopenharmony_ci        index++;
12206f6ba60Sopenharmony_ci        cpuData->steal_ = fields_[index];
12306f6ba60Sopenharmony_ci        index++;
12406f6ba60Sopenharmony_ci        cpuData->hardirq_ = fields_[index];
12506f6ba60Sopenharmony_ci        index++;
12606f6ba60Sopenharmony_ci        cpuData->softirq_ = fields_[index];
12706f6ba60Sopenharmony_ci        index++;
12806f6ba60Sopenharmony_ci        cpuData->guest_ = fields_[index];
12906f6ba60Sopenharmony_ci        index++;
13006f6ba60Sopenharmony_ci        cpuData->guestNice_ = fields_[index];
13106f6ba60Sopenharmony_ci        cpuDatas_.push_back(cpuData);
13206f6ba60Sopenharmony_ci        fields_.clear();
13306f6ba60Sopenharmony_ci        return true;
13406f6ba60Sopenharmony_ci    }
13506f6ba60Sopenharmony_ci
13606f6ba60Sopenharmony_ci    return false;
13706f6ba60Sopenharmony_ci}
13806f6ba60Sopenharmony_ci
13906f6ba60Sopenharmony_cibool IoStats::ParseIoStats()
14006f6ba60Sopenharmony_ci{
14106f6ba60Sopenharmony_ci    std::ifstream input(DISKSTATS_PATH, std::ios::in);
14206f6ba60Sopenharmony_ci    CHECK_TRUE(!input.fail(), false, "%s:%d open failed, errno = %d", __func__, __LINE__, errno);
14306f6ba60Sopenharmony_ci    do {
14406f6ba60Sopenharmony_ci        if (!input.good()) {
14506f6ba60Sopenharmony_ci            return false;
14606f6ba60Sopenharmony_ci        }
14706f6ba60Sopenharmony_ci        std::string line;
14806f6ba60Sopenharmony_ci        getline(input, line);
14906f6ba60Sopenharmony_ci        line += '\n';
15006f6ba60Sopenharmony_ci        GetIoStats(line);
15106f6ba60Sopenharmony_ci    } while (!input.eof());
15206f6ba60Sopenharmony_ci    input.close();
15306f6ba60Sopenharmony_ci
15406f6ba60Sopenharmony_ci    return true;
15506f6ba60Sopenharmony_ci}
15606f6ba60Sopenharmony_ci
15706f6ba60Sopenharmony_cibool IoStats::GetIoStats(std::string& line)
15806f6ba60Sopenharmony_ci{
15906f6ba60Sopenharmony_ci    std::string name;
16006f6ba60Sopenharmony_ci    auto ioInfo = std::make_shared<DiskStats>();
16106f6ba60Sopenharmony_ci    CHECK_NOTNULL(ioInfo, false, "create DiskStats FAILED!");
16206f6ba60Sopenharmony_ci
16306f6ba60Sopenharmony_ci    if (ParseLineFields(line, name) > 0) {
16406f6ba60Sopenharmony_ci        int index = 0;
16506f6ba60Sopenharmony_ci        ioInfo->major_ = fields_[index];
16606f6ba60Sopenharmony_ci        index++;
16706f6ba60Sopenharmony_ci        ioInfo->minor_ = fields_[index];
16806f6ba60Sopenharmony_ci        index++;
16906f6ba60Sopenharmony_ci        ioInfo->deviceName_ = name;
17006f6ba60Sopenharmony_ci
17106f6ba60Sopenharmony_ci        ioInfo->rSucc_ = fields_[index];
17206f6ba60Sopenharmony_ci        index++;
17306f6ba60Sopenharmony_ci        ioInfo->rMerged_  = fields_[index];
17406f6ba60Sopenharmony_ci        index++;
17506f6ba60Sopenharmony_ci        ioInfo->rSectors_ = fields_[index];
17606f6ba60Sopenharmony_ci        index++;
17706f6ba60Sopenharmony_ci        ioInfo->timeOfRead_ = fields_[index];
17806f6ba60Sopenharmony_ci        index++;
17906f6ba60Sopenharmony_ci
18006f6ba60Sopenharmony_ci        ioInfo->wSucc_ = fields_[index];
18106f6ba60Sopenharmony_ci        index++;
18206f6ba60Sopenharmony_ci        ioInfo->wMerged_  = fields_[index];
18306f6ba60Sopenharmony_ci        index++;
18406f6ba60Sopenharmony_ci        ioInfo->wSectors_ = fields_[index];
18506f6ba60Sopenharmony_ci        index++;
18606f6ba60Sopenharmony_ci        ioInfo->timeOfWrite_ = fields_[index];
18706f6ba60Sopenharmony_ci        index++;
18806f6ba60Sopenharmony_ci
18906f6ba60Sopenharmony_ci        ioInfo->ios_ = fields_[index];
19006f6ba60Sopenharmony_ci        index++;
19106f6ba60Sopenharmony_ci        ioInfo->timeOfIo_ = fields_[index];
19206f6ba60Sopenharmony_ci        index++;
19306f6ba60Sopenharmony_ci        ioInfo->weighted_ = fields_[index];
19406f6ba60Sopenharmony_ci        index++;
19506f6ba60Sopenharmony_ci
19606f6ba60Sopenharmony_ci        ioInfo->dSucc_ = fields_[index];
19706f6ba60Sopenharmony_ci        index++;
19806f6ba60Sopenharmony_ci        ioInfo->dMerged_ = fields_[index];
19906f6ba60Sopenharmony_ci        index++;
20006f6ba60Sopenharmony_ci        ioInfo->dSectors_ = fields_[index];
20106f6ba60Sopenharmony_ci        index++;
20206f6ba60Sopenharmony_ci        ioInfo->timeOfd_ = fields_[index];
20306f6ba60Sopenharmony_ci        index++;
20406f6ba60Sopenharmony_ci
20506f6ba60Sopenharmony_ci        ioInfo->flushSucc_ = fields_[index];
20606f6ba60Sopenharmony_ci        index++;
20706f6ba60Sopenharmony_ci        ioInfo->timeOfFlush_ = fields_[index];
20806f6ba60Sopenharmony_ci
20906f6ba60Sopenharmony_ci        ioDatas_.push_back(ioInfo);
21006f6ba60Sopenharmony_ci        fields_.clear();
21106f6ba60Sopenharmony_ci        return true;
21206f6ba60Sopenharmony_ci    }
21306f6ba60Sopenharmony_ci#if __DEBUG__
21406f6ba60Sopenharmony_ci    char debugName[128];
21506f6ba60Sopenharmony_ci    uint64_t rMergesOrIo = 0;
21606f6ba60Sopenharmony_ci    uint64_t rwIos = 0;
21706f6ba60Sopenharmony_ci    uint64_t rTicksOrw = 0;
21806f6ba60Sopenharmony_ci    auto debugIoInfo = std::make_shared<DiskStats>();
21906f6ba60Sopenharmony_ci    int ret = sscanf_s(line.c_str(), "%u %u %s %lu %lu %lu %" PRIu64 " %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
22006f6ba60Sopenharmony_ci                       &debugIoInfo->major_, &debugIoInfo->minor_, debugName, sizeof(debugName),
22106f6ba60Sopenharmony_ci                       &debugIoInfo->rSucc_, &rMergesOrIo, &rwIos, &rTicksOrw,
22206f6ba60Sopenharmony_ci                       &debugIoInfo->wSucc_, &debugIoInfo->wMerged_,
22306f6ba60Sopenharmony_ci                       &debugIoInfo->wSectors_, &debugIoInfo->timeOfWrite_,
22406f6ba60Sopenharmony_ci                       &debugIoInfo->ios_, &debugIoInfo->timeOfIo_, &debugIoInfo->weighted_,
22506f6ba60Sopenharmony_ci                       &debugIoInfo->dSucc_, &debugIoInfo->dMerged_,
22606f6ba60Sopenharmony_ci                       &debugIoInfo->dSectors_, &debugIoInfo->timeOfd_,
22706f6ba60Sopenharmony_ci                       &debugIoInfo->flushSucc_, &debugIoInfo->timeOfFlush_);
22806f6ba60Sopenharmony_ci    if (ret == NUM_SEVEN) {
22906f6ba60Sopenharmony_ci        debugIoInfo->rSectors_ = rMergesOrIo;
23006f6ba60Sopenharmony_ci        debugIoInfo->wSucc_ = rwIos;
23106f6ba60Sopenharmony_ci        debugIoInfo->wSectors_ = rTicksOrw;
23206f6ba60Sopenharmony_ci    } else {
23306f6ba60Sopenharmony_ci        debugIoInfo->rMerged_  = rMergesOrIo;
23406f6ba60Sopenharmony_ci        debugIoInfo->rSectors_ = rwIos;
23506f6ba60Sopenharmony_ci        debugIoInfo->timeOfRead_ = rTicksOrw;
23606f6ba60Sopenharmony_ci    }
23706f6ba60Sopenharmony_ci    debugIoInfo->deviceName_ = std::string(name);
23806f6ba60Sopenharmony_ci    ioDatas_.push_back(debugIoInfo);
23906f6ba60Sopenharmony_ci#endif
24006f6ba60Sopenharmony_ci
24106f6ba60Sopenharmony_ci    return false;
24206f6ba60Sopenharmony_ci}
24306f6ba60Sopenharmony_ci
24406f6ba60Sopenharmony_cibool IoStats::ParseIoStatsEx()
24506f6ba60Sopenharmony_ci{
24606f6ba60Sopenharmony_ci    return true;
24706f6ba60Sopenharmony_ci}
24806f6ba60Sopenharmony_ci
24906f6ba60Sopenharmony_cidouble IoStats::KeepTowDigits(const uint64_t& data, uint64_t div)
25006f6ba60Sopenharmony_ci{
25106f6ba60Sopenharmony_ci    double result = 0.00;
25206f6ba60Sopenharmony_ci    if (data <= 0 || div == 0) {
25306f6ba60Sopenharmony_ci        return result;
25406f6ba60Sopenharmony_ci    }
25506f6ba60Sopenharmony_ci    double ddiv = div;
25606f6ba60Sopenharmony_ci    if (ddiv != NUM_TWO) {
25706f6ba60Sopenharmony_ci        ddiv = div * NUM_ZERO_POINTZEROONE;
25806f6ba60Sopenharmony_ci    }
25906f6ba60Sopenharmony_ci    result = static_cast<double>(data) / ddiv;
26006f6ba60Sopenharmony_ci    return result;
26106f6ba60Sopenharmony_ci}
26206f6ba60Sopenharmony_ci
26306f6ba60Sopenharmony_cibool IoStats::FindFirstNum(char** p)
26406f6ba60Sopenharmony_ci{
26506f6ba60Sopenharmony_ci    CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
26606f6ba60Sopenharmony_ci    while (**p > '9' || **p < '0') {
26706f6ba60Sopenharmony_ci        if (**p == '\0' || **p == '\n') {
26806f6ba60Sopenharmony_ci            return false;
26906f6ba60Sopenharmony_ci        }
27006f6ba60Sopenharmony_ci        (*p)++;
27106f6ba60Sopenharmony_ci    }
27206f6ba60Sopenharmony_ci    return true;
27306f6ba60Sopenharmony_ci}
27406f6ba60Sopenharmony_ci
27506f6ba60Sopenharmony_cibool IoStats::RemoveSpaces(char** p)
27606f6ba60Sopenharmony_ci{
27706f6ba60Sopenharmony_ci    CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
27806f6ba60Sopenharmony_ci    if (**p == '\0' || **p == '\n') {
27906f6ba60Sopenharmony_ci        return false;
28006f6ba60Sopenharmony_ci    }
28106f6ba60Sopenharmony_ci    while (**p == ' ') {
28206f6ba60Sopenharmony_ci        (*p)++;
28306f6ba60Sopenharmony_ci        if (**p == '\0' || **p == '\n') {
28406f6ba60Sopenharmony_ci            return false;
28506f6ba60Sopenharmony_ci        }
28606f6ba60Sopenharmony_ci    }
28706f6ba60Sopenharmony_ci    return true;
28806f6ba60Sopenharmony_ci}
28906f6ba60Sopenharmony_ci
29006f6ba60Sopenharmony_ciuint32_t IoStats::ParseLineFields(const std::string& line, std::string& name)
29106f6ba60Sopenharmony_ci{
29206f6ba60Sopenharmony_ci    uint64_t num;
29306f6ba60Sopenharmony_ci    uint32_t count = 0;
29406f6ba60Sopenharmony_ci    char* end = nullptr;
29506f6ba60Sopenharmony_ci    char* pTmp = const_cast<char*>(line.c_str());
29606f6ba60Sopenharmony_ci
29706f6ba60Sopenharmony_ci    fields_.clear();
29806f6ba60Sopenharmony_ci    while (pTmp != nullptr && *pTmp != '\n') {
29906f6ba60Sopenharmony_ci        CHECK_TRUE(RemoveSpaces(&pTmp), count, "%s: RemoveSpaces failed!", __func__);
30006f6ba60Sopenharmony_ci        if (*pTmp >= 'a' && *pTmp <= 'z') {
30106f6ba60Sopenharmony_ci            char field[64];
30206f6ba60Sopenharmony_ci            int len = 0;
30306f6ba60Sopenharmony_ci            int ret = sscanf_s(pTmp, "%63s %n", field, sizeof(field), &len);
30406f6ba60Sopenharmony_ci            if (ret == 1 && *field) {
30506f6ba60Sopenharmony_ci                name = std::string(field, strlen(field));
30606f6ba60Sopenharmony_ci                pTmp += len;
30706f6ba60Sopenharmony_ci            }
30806f6ba60Sopenharmony_ci        }
30906f6ba60Sopenharmony_ci        CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
31006f6ba60Sopenharmony_ci        num = strtoull(pTmp, &end, DEC_BASE);
31106f6ba60Sopenharmony_ci        CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
31206f6ba60Sopenharmony_ci        fields_.push_back(num);
31306f6ba60Sopenharmony_ci        pTmp = end;
31406f6ba60Sopenharmony_ci        count++;
31506f6ba60Sopenharmony_ci    }
31606f6ba60Sopenharmony_ci    return count;
31706f6ba60Sopenharmony_ci}
31806f6ba60Sopenharmony_ci
31906f6ba60Sopenharmony_ciuint32_t IoStats::ParseLineFields(const std::string& line)
32006f6ba60Sopenharmony_ci{
32106f6ba60Sopenharmony_ci    uint64_t num;
32206f6ba60Sopenharmony_ci    uint32_t count = 0;
32306f6ba60Sopenharmony_ci    char* end = nullptr;
32406f6ba60Sopenharmony_ci    char* pTmp = const_cast<char*>(line.c_str());
32506f6ba60Sopenharmony_ci
32606f6ba60Sopenharmony_ci    while (pTmp != nullptr && *pTmp != '\n') {
32706f6ba60Sopenharmony_ci        CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
32806f6ba60Sopenharmony_ci        num = static_cast<uint32_t>(strtoull(pTmp, &end, DEC_BASE));
32906f6ba60Sopenharmony_ci        CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
33006f6ba60Sopenharmony_ci        fields_.push_back(num);
33106f6ba60Sopenharmony_ci        pTmp = end;
33206f6ba60Sopenharmony_ci        count++;
33306f6ba60Sopenharmony_ci    }
33406f6ba60Sopenharmony_ci    return count;
33506f6ba60Sopenharmony_ci}