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