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