1 /*
2 * Copyright (c) 2021 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 "diskio_data_plugin.h"
17
18 #include <ctime>
19
20 #include "buffer_splitter.h"
21
22 namespace {
23 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
24 } // namespace
25
DiskioDataPlugin()26 DiskioDataPlugin::DiskioDataPlugin()
27 {
28 ioEntry_ = nullptr;
29 buffer_ = nullptr;
30 path_ = "/proc/vmstat";
31 err_ = -1;
32 prevRdSectorsKb_ = 0;
33 prevWrSectorsKb_ = 0;
34 prevTimestamp_.set_tv_sec(0);
35 prevTimestamp_.set_tv_nsec(0);
36 }
37
~DiskioDataPlugin()38 DiskioDataPlugin::~DiskioDataPlugin()
39 {
40 HILOG_INFO(LOG_CORE, "%s:~DiskioDataPlugin!", __func__);
41 if (buffer_ != nullptr) {
42 free(buffer_);
43 buffer_ = nullptr;
44 }
45 }
46
Start(const uint8_t * configData,uint32_t configSize)47 int DiskioDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
48 {
49 buffer_ = malloc(READ_BUFFER_SIZE);
50 CHECK_NOTNULL(buffer_, RET_FAIL, "%s:malloc buffer_ failed!", __func__);
51
52 CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
53 "%s:parseFromArray failed!", __func__);
54
55 if (protoConfig_.report_io_stats()) {
56 ioEntry_ = std::make_shared<IoStats>(protoConfig_.report_io_stats());
57 }
58 HILOG_INFO(LOG_CORE, "%s:start success!", __func__);
59 return RET_SUCC;
60 }
61
Report(uint8_t * data,uint32_t dataSize)62 int DiskioDataPlugin::Report(uint8_t* data, uint32_t dataSize)
63 {
64 DiskioData dataProto;
65 uint32_t length;
66
67 WriteDiskioData(dataProto);
68
69 if (protoConfig_.report_io_stats() && ioEntry_ != nullptr) {
70 ioEntry_->GetIoData();
71 ioEntry_->PutPluginStatsData(dataProto.mutable_statsdata());
72 }
73
74 length = dataProto.ByteSizeLong();
75 if (length > dataSize) {
76 return -length;
77 }
78 if (dataProto.SerializeToArray(data, length) > 0) {
79 return length;
80 }
81 return 0;
82 }
83
Stop()84 int DiskioDataPlugin::Stop()
85 {
86 if (buffer_ != nullptr) {
87 free(buffer_);
88 buffer_ = nullptr;
89 }
90 if (ioEntry_ != nullptr) {
91 ioEntry_.reset();
92 ioEntry_ = nullptr;
93 }
94 HILOG_INFO(LOG_CORE, "%s:plugin:stop success!", __func__);
95 return 0;
96 }
97
ReadFile(std::string & fileName)98 int32_t DiskioDataPlugin::ReadFile(std::string& fileName)
99 {
100 int fd = -1;
101 ssize_t bytesRead = 0;
102 char realPath[PATH_MAX + 1] = {0};
103 CHECK_TRUE((fileName.length() < PATH_MAX) && (realpath(fileName.c_str(), realPath) != nullptr), RET_FAIL,
104 "%s:path is invalid: %s, errno=%d", __func__, fileName.c_str(), errno);
105 fd = open(realPath, O_RDONLY | O_CLOEXEC);
106 if (fd == -1) {
107 HILOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno=%d", __func__, fileName.c_str(), errno);
108 err_ = errno;
109 return RET_FAIL;
110 }
111 if (buffer_ == nullptr) {
112 HILOG_ERROR(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
113 err_ = RET_NULL_ADDR;
114 close(fd);
115 return RET_FAIL;
116 }
117 bytesRead = read(fd, buffer_, READ_BUFFER_SIZE - 1);
118 if (bytesRead <= 0) {
119 close(fd);
120 HILOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, fileName.c_str(), errno);
121 err_ = errno;
122 return RET_FAIL;
123 }
124 close(fd);
125
126 return bytesRead;
127 }
128
SetTimestamp(CollectTimeStamp & prevTimestamp,CollectTimeStamp & timestamp)129 void DiskioDataPlugin::SetTimestamp(CollectTimeStamp& prevTimestamp, CollectTimeStamp& timestamp)
130 {
131 timespec time;
132 clock_gettime(CLOCK_MONOTONIC, &time);
133 timestamp.set_tv_sec(time.tv_sec);
134 timestamp.set_tv_nsec(time.tv_nsec);
135 prevTimestamp.set_tv_sec(prevTimestamp_.tv_sec());
136 prevTimestamp.set_tv_nsec(prevTimestamp_.tv_nsec());
137 prevTimestamp_.set_tv_sec(time.tv_sec);
138 prevTimestamp_.set_tv_nsec(time.tv_nsec);
139 }
140
SetDiskioData(DiskioData & diskioData,const char * pFile,uint32_t fileLen)141 void DiskioDataPlugin::SetDiskioData(DiskioData& diskioData, const char* pFile, uint32_t fileLen)
142 {
143 BufferSplitter totalbuffer(const_cast<char*>(pFile), fileLen + 1);
144 int64_t rd_sectors_kb = 0;
145 int64_t wr_sectors_kb = 0;
146
147 do {
148 totalbuffer.NextWord(' ');
149 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
150 if (strcmp(curWord.c_str(), "pgpgin") == 0) {
151 if (!totalbuffer.NextWord('\n')) {
152 HILOG_ERROR(LOG_CORE, "%s:failed to get pgpgin, CurWord() = %s", __func__, totalbuffer.CurWord());
153 break;
154 }
155 curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
156 rd_sectors_kb = atoi(curWord.c_str());
157 } else if (strcmp(curWord.c_str(), "pgpgout") == 0) {
158 if (!totalbuffer.NextWord('\n')) {
159 HILOG_ERROR(LOG_CORE, "%s:failed to get pgpgout, CurWord() = %s", __func__, totalbuffer.CurWord());
160 break;
161 }
162 curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize());
163 wr_sectors_kb = atoi(curWord.c_str());
164 }
165 } while (totalbuffer.NextLine());
166
167 // 前一次系统从磁盘调入的总KB数rd1,通过时间间隔t内KB增量计算磁盘读取速率(rd2-rd1)/t
168 diskioData.set_prev_rd_sectors_kb(prevRdSectorsKb_);
169 // 前一次系统调出到磁盘的总KB数wr1,通过时间间隔t内KB增量计算磁盘写入速率(wr2-wr1)/t
170 diskioData.set_prev_wr_sectors_kb(prevWrSectorsKb_);
171 diskioData.set_rd_sectors_kb(rd_sectors_kb); // 当前系统从磁盘调入的总KB数rd2
172 diskioData.set_wr_sectors_kb(wr_sectors_kb); // 当前系统调出到磁盘的总KB数wr2
173 prevRdSectorsKb_ = rd_sectors_kb;
174 prevWrSectorsKb_ = wr_sectors_kb;
175 auto* prevTimestamp = diskioData.mutable_prev_timestamp();
176 auto* timestamp = diskioData.mutable_timestamp();
177 SetTimestamp(*prevTimestamp, *timestamp); // 设置前一次时间戳和当前时间戳,以便计算两次获取数据的时间间隔t
178 }
179
WriteDiskioData(DiskioData & data)180 void DiskioDataPlugin::WriteDiskioData(DiskioData& data)
181 {
182 int32_t ret = ReadFile(path_);
183 if (ret == RET_FAIL) {
184 return;
185 }
186 if ((buffer_ == nullptr) || (ret == 0)) {
187 return;
188 }
189
190 SetDiskioData(data, (char*)buffer_, ret);
191 }