• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #include "io_stats.h"
16 #include "securec.h"
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 
23 namespace {
24 const int NUM_ONEHUNDRED = 100;
25 const double NUM_ZERO_POINTZEROONE = 0.01;
26 #if __DEBUG__
27 const char* SYSTIME_PATH = "/data/local/tmp/systimes";
28 const char* CPU_PATH = "/data/local/tmp/cpustats";
29 const char* DISKSTATS_PATH = "/data/local/tmp/diskstats";
30 const int NUM_SEVEN = 7;
31 #else
32 const char* SYSTIME_PATH = "/proc/uptime";
33 const char* CPU_PATH = "/proc/stat";
34 const char* DISKSTATS_PATH = "/proc/diskstats";
35 #endif // #if __DEBUG__
36 const int DEC_BASE = 10;
37 } // namespace
38 
IoStats(DiskioConfig::IoReportType type)39 IoStats::IoStats(DiskioConfig::IoReportType type) : type_(type)
40 {
41     sysTime_ = GetSystime();
42 }
43 
GetSystime()44 uint64_t IoStats::GetSystime()
45 {
46     uint64_t systime = 1;
47     std::ifstream input(SYSTIME_PATH, std::ios::in);
48     CHECK_TRUE(!input.fail(), systime, "%s:open %s failed, errno = %d", __func__, SYSTIME_PATH, errno);
49     do {
50         if (!input.good()) {
51             return systime;
52         }
53         std::string line;
54         getline(input, line);
55         line += '\n';
56 
57         uint64_t nsec = 0;
58         uint64_t ncent = 0;
59         if (ParseLineFields(line) > 0) {
60             nsec = fields_[0];
61             ncent = fields_[1];
62             systime = nsec * NUM_ONEHUNDRED + ncent;
63         }
64         fields_.clear();
65     } while (0);
66     input.close();
67 
68     return systime;
69 }
70 
GetIoData()71 bool IoStats::GetIoData()
72 {
73     ParseCpuStats();
74     if (type_ == DiskioConfig::IO_REPORT) {
75         ParseIoStats();
76     } else if (type_ == DiskioConfig::IO_REPORT_EX) {
77         ParseIoStatsEx();
78     }
79     return true;
80 }
81 
ParseCpuStats()82 bool IoStats::ParseCpuStats()
83 {
84     std::ifstream input(CPU_PATH, std::ios::in);
85     CHECK_TRUE(!input.fail(), false, "%s: open %s failed, errno = %d", __func__, CPU_PATH, errno);
86     do {
87         if (!input.good()) {
88             return false;
89         }
90         std::string line;
91         getline(input, line);
92 
93         auto pos = line.find("cpu");
94         if (pos != std::string::npos) {
95             line += '\n';
96             GetCpuStats(line);
97         }
98     } while (!input.eof());
99     input.close();
100 
101     return true;
102 }
103 
GetCpuStats(std::string & line)104 bool IoStats::GetCpuStats(std::string& line)
105 {
106     std::string name;
107     auto cpuData = std::make_shared<ProcStats>();
108     CHECK_NOTNULL(cpuData, false, "create ProcStats FAILED!");
109 
110     if (ParseLineFields(line, name) > 0) {
111         int index = 0;
112         cpuData->name_ = name;
113         cpuData->user_ = fields_[index];
114         index++;
115         cpuData->nice_ = fields_[index];
116         index++;
117         cpuData->system_ = fields_[index];
118         index++;
119         cpuData->idle_ = fields_[index];
120         index++;
121         cpuData->iowait_ = fields_[index];
122         index++;
123         cpuData->steal_ = fields_[index];
124         index++;
125         cpuData->hardirq_ = fields_[index];
126         index++;
127         cpuData->softirq_ = fields_[index];
128         index++;
129         cpuData->guest_ = fields_[index];
130         index++;
131         cpuData->guestNice_ = fields_[index];
132         cpuDatas_.push_back(cpuData);
133         fields_.clear();
134         return true;
135     }
136 
137     return false;
138 }
139 
ParseIoStats()140 bool IoStats::ParseIoStats()
141 {
142     std::ifstream input(DISKSTATS_PATH, std::ios::in);
143     CHECK_TRUE(!input.fail(), false, "%s:%d open failed, errno = %d", __func__, __LINE__, errno);
144     do {
145         if (!input.good()) {
146             return false;
147         }
148         std::string line;
149         getline(input, line);
150         line += '\n';
151         GetIoStats(line);
152     } while (!input.eof());
153     input.close();
154 
155     return true;
156 }
157 
GetIoStats(std::string & line)158 bool IoStats::GetIoStats(std::string& line)
159 {
160     std::string name;
161     auto ioInfo = std::make_shared<DiskStats>();
162     CHECK_NOTNULL(ioInfo, false, "create DiskStats FAILED!");
163 
164     if (ParseLineFields(line, name) > 0) {
165         int index = 0;
166         ioInfo->major_ = fields_[index];
167         index++;
168         ioInfo->minor_ = fields_[index];
169         index++;
170         ioInfo->deviceName_ = name;
171 
172         ioInfo->rSucc_ = fields_[index];
173         index++;
174         ioInfo->rMerged_  = fields_[index];
175         index++;
176         ioInfo->rSectors_ = fields_[index];
177         index++;
178         ioInfo->timeOfRead_ = fields_[index];
179         index++;
180 
181         ioInfo->wSucc_ = fields_[index];
182         index++;
183         ioInfo->wMerged_  = fields_[index];
184         index++;
185         ioInfo->wSectors_ = fields_[index];
186         index++;
187         ioInfo->timeOfWrite_ = fields_[index];
188         index++;
189 
190         ioInfo->ios_ = fields_[index];
191         index++;
192         ioInfo->timeOfIo_ = fields_[index];
193         index++;
194         ioInfo->weighted_ = fields_[index];
195         index++;
196 
197         ioInfo->dSucc_ = fields_[index];
198         index++;
199         ioInfo->dMerged_ = fields_[index];
200         index++;
201         ioInfo->dSectors_ = fields_[index];
202         index++;
203         ioInfo->timeOfd_ = fields_[index];
204         index++;
205 
206         ioInfo->flushSucc_ = fields_[index];
207         index++;
208         ioInfo->timeOfFlush_ = fields_[index];
209 
210         ioDatas_.push_back(ioInfo);
211         fields_.clear();
212         return true;
213     }
214 #if __DEBUG__
215     char debugName[128];
216     uint64_t rMergesOrIo = 0;
217     uint64_t rwIos = 0;
218     uint64_t rTicksOrw = 0;
219     auto debugIoInfo = std::make_shared<DiskStats>();
220     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",
221                        &debugIoInfo->major_, &debugIoInfo->minor_, debugName, sizeof(debugName),
222                        &debugIoInfo->rSucc_, &rMergesOrIo, &rwIos, &rTicksOrw,
223                        &debugIoInfo->wSucc_, &debugIoInfo->wMerged_,
224                        &debugIoInfo->wSectors_, &debugIoInfo->timeOfWrite_,
225                        &debugIoInfo->ios_, &debugIoInfo->timeOfIo_, &debugIoInfo->weighted_,
226                        &debugIoInfo->dSucc_, &debugIoInfo->dMerged_,
227                        &debugIoInfo->dSectors_, &debugIoInfo->timeOfd_,
228                        &debugIoInfo->flushSucc_, &debugIoInfo->timeOfFlush_);
229     if (ret == NUM_SEVEN) {
230         debugIoInfo->rSectors_ = rMergesOrIo;
231         debugIoInfo->wSucc_ = rwIos;
232         debugIoInfo->wSectors_ = rTicksOrw;
233     } else {
234         debugIoInfo->rMerged_  = rMergesOrIo;
235         debugIoInfo->rSectors_ = rwIos;
236         debugIoInfo->timeOfRead_ = rTicksOrw;
237     }
238     debugIoInfo->deviceName_ = std::string(name);
239     ioDatas_.push_back(debugIoInfo);
240 #endif
241 
242     return false;
243 }
244 
ParseIoStatsEx()245 bool IoStats::ParseIoStatsEx()
246 {
247     return true;
248 }
249 
KeepTowDigits(const uint64_t & data,uint64_t div)250 double IoStats::KeepTowDigits(const uint64_t& data, uint64_t div)
251 {
252     double result = 0.00;
253     if (data <= 0 || div == 0) {
254         return result;
255     }
256     double ddiv = div;
257     if (ddiv != NUM_TWO) {
258         ddiv = div * NUM_ZERO_POINTZEROONE;
259     }
260     result = static_cast<double>(data) / ddiv;
261     return result;
262 }
263 
FindFirstNum(char ** p)264 bool IoStats::FindFirstNum(char** p)
265 {
266     CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
267     while (**p > '9' || **p < '0') {
268         if (**p == '\0' || **p == '\n') {
269             return false;
270         }
271         (*p)++;
272     }
273     return true;
274 }
275 
RemoveSpaces(char ** p)276 bool IoStats::RemoveSpaces(char** p)
277 {
278     CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
279     if (**p == '\0' || **p == '\n') {
280         return false;
281     }
282     while (**p == ' ') {
283         (*p)++;
284         if (**p == '\0' || **p == '\n') {
285             return false;
286         }
287     }
288     return true;
289 }
290 
ParseLineFields(const std::string & line,std::string & name)291 uint32_t IoStats::ParseLineFields(const std::string& line, std::string& name)
292 {
293     uint64_t num;
294     uint32_t count = 0;
295     char* end = nullptr;
296     char* pTmp = const_cast<char*>(line.c_str());
297 
298     fields_.clear();
299     while (pTmp != nullptr && *pTmp != '\n') {
300         CHECK_TRUE(RemoveSpaces(&pTmp), count, "%s: RemoveSpaces failed!", __func__);
301         if (*pTmp >= 'a' && *pTmp <= 'z') {
302             char field[64];
303             int len = 0;
304             int ret = sscanf_s(pTmp, "%63s %n", field, sizeof(field), &len);
305             if (ret == 1 && *field) {
306                 name = std::string(field, strlen(field));
307                 pTmp += len;
308             }
309         }
310         CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
311         num = strtoull(pTmp, &end, DEC_BASE);
312         CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
313         fields_.push_back(num);
314         pTmp = end;
315         count++;
316     }
317     return count;
318 }
319 
ParseLineFields(const std::string & line)320 uint32_t IoStats::ParseLineFields(const std::string& line)
321 {
322     uint64_t num;
323     uint32_t count = 0;
324     char* end = nullptr;
325     char* pTmp = const_cast<char*>(line.c_str());
326 
327     while (pTmp != nullptr && *pTmp != '\n') {
328         CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
329         num = static_cast<uint32_t>(strtoull(pTmp, &end, DEC_BASE));
330         CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
331         fields_.push_back(num);
332         pTmp = end;
333         count++;
334     }
335     return count;
336 }