• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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_TWO = 2;
25 const int NUM_ONEHUNDRED = 100;
26 const double NUM_ZERO_POINTZEROONE = 0.01;
27 #if __DEBUG__
28 const char* SYSTIME_PATH = "/data/local/tmp/systimes";
29 const char* CPU_PATH = "/data/local/tmp/cpustats";
30 const char* DISKSTATS_PATH = "/data/local/tmp/diskstats";
31 const int NUM_SEVEN = 7;
32 #else
33 const char* SYSTIME_PATH = "/proc/uptime";
34 const char* CPU_PATH = "/proc/stat";
35 const char* DISKSTATS_PATH = "/proc/diskstats";
36 #endif // #if __DEBUG__
37 const int DEC_BASE = 10;
38 } // namespace
39 
IoStats(DiskioConfig::IoReportType type)40 IoStats::IoStats(DiskioConfig::IoReportType type) : type_(type)
41 {
42     sysTime_ = GetSystime();
43 }
44 
GetSystime()45 uint64_t IoStats::GetSystime()
46 {
47     uint64_t systime = 1;
48     std::ifstream input(SYSTIME_PATH, std::ios::in);
49     if (input.fail()) {
50         HILOG_ERROR(LOG_CORE, "%s:open %s failed, errno = %d", __func__, SYSTIME_PATH, errno);
51         return systime;
52     }
53     do {
54         if (!input.good()) {
55             return systime;
56         }
57         std::string line;
58         getline(input, line);
59         line += '\n';
60 
61         uint64_t nsec = 0;
62         uint64_t ncent = 0;
63         if (ParseLineFields(line) > 0) {
64             nsec = fields_[0];
65             ncent = fields_[1];
66             systime = nsec * NUM_ONEHUNDRED + ncent;
67         }
68         fields_.clear();
69     } while (0);
70     input.close();
71 
72     return systime;
73 }
74 
GetIoData()75 bool IoStats::GetIoData()
76 {
77     ParseCpuStats();
78     if (type_ == DiskioConfig::IO_REPORT) {
79         ParseIoStats();
80     } else if (type_ == DiskioConfig::IO_REPORT_EX) {
81         ParseIoStatsEx();
82     }
83     return true;
84 }
85 
ParseCpuStats()86 bool IoStats::ParseCpuStats()
87 {
88     std::ifstream input(CPU_PATH, std::ios::in);
89     if (input.fail()) {
90         HILOG_ERROR(LOG_CORE, "%s: open %s failed, errno = %d", __func__, CPU_PATH, errno);
91         return false;
92     }
93     do {
94         if (!input.good()) {
95             return false;
96         }
97         std::string line;
98         getline(input, line);
99 
100         auto pos = line.find("cpu");
101         if (pos != std::string::npos) {
102             line += '\n';
103             GetCpuStats(line);
104         }
105     } while (!input.eof());
106     input.close();
107 
108     return true;
109 }
110 
GetCpuStats(std::string & line)111 bool IoStats::GetCpuStats(std::string& line)
112 {
113     std::string name;
114     auto cpuData = std::make_shared<ProcStats>();
115     CHECK_NOTNULL(cpuData, false, "create ProcStats FAILED!");
116 
117     if (ParseLineFields(line, name) > 0) {
118         int index = 0;
119         cpuData->name_ = name;
120         cpuData->user_ = fields_[index];
121         index++;
122         cpuData->nice_ = fields_[index];
123         index++;
124         cpuData->system_ = fields_[index];
125         index++;
126         cpuData->idle_ = fields_[index];
127         index++;
128         cpuData->iowait_ = fields_[index];
129         index++;
130         cpuData->steal_ = fields_[index];
131         index++;
132         cpuData->hardirq_ = fields_[index];
133         index++;
134         cpuData->softirq_ = fields_[index];
135         index++;
136         cpuData->guest_ = fields_[index];
137         index++;
138         cpuData->guestNice_ = fields_[index];
139         cpuDatas_.push_back(cpuData);
140         fields_.clear();
141         return true;
142     }
143 
144     return false;
145 }
146 
ParseIoStats()147 bool IoStats::ParseIoStats()
148 {
149     std::ifstream input(DISKSTATS_PATH, std::ios::in);
150     if (input.fail()) {
151         HILOG_ERROR(LOG_CORE, "%s:%d open failed, errno = %d", __func__, __LINE__, errno);
152         return false;
153     }
154     do {
155         if (!input.good()) {
156             return false;
157         }
158         std::string line;
159         getline(input, line);
160         line += '\n';
161         GetIoStats(line);
162     } while (!input.eof());
163     input.close();
164 
165     return true;
166 }
167 
GetIoStats(std::string & line)168 bool IoStats::GetIoStats(std::string& line)
169 {
170     std::string name;
171     auto ioInfo = std::make_shared<DiskStats>();
172     CHECK_NOTNULL(ioInfo, false, "create DiskStats FAILED!");
173 
174     if (ParseLineFields(line, name) > 0) {
175         int index = 0;
176         ioInfo->major_ = fields_[index];
177         index++;
178         ioInfo->minor_ = fields_[index];
179         index++;
180         ioInfo->deviceName_ = name;
181 
182         ioInfo->rSucc_ = fields_[index];
183         index++;
184         ioInfo->rMerged_  = fields_[index];
185         index++;
186         ioInfo->rSectors_ = fields_[index];
187         index++;
188         ioInfo->timeOfRead_ = fields_[index];
189         index++;
190 
191         ioInfo->wSucc_ = fields_[index];
192         index++;
193         ioInfo->wMerged_  = fields_[index];
194         index++;
195         ioInfo->wSectors_ = fields_[index];
196         index++;
197         ioInfo->timeOfWrite_ = fields_[index];
198         index++;
199 
200         ioInfo->ios_ = fields_[index];
201         index++;
202         ioInfo->timeOfIo_ = fields_[index];
203         index++;
204         ioInfo->weighted_ = fields_[index];
205         index++;
206 
207         ioInfo->dSucc_ = fields_[index];
208         index++;
209         ioInfo->dMerged_ = fields_[index];
210         index++;
211         ioInfo->dSectors_ = fields_[index];
212         index++;
213         ioInfo->timeOfd_ = fields_[index];
214         index++;
215 
216         ioInfo->flushSucc_ = fields_[index];
217         index++;
218         ioInfo->timeOfFlush_ = fields_[index];
219 
220         ioDatas_.push_back(ioInfo);
221         fields_.clear();
222         return true;
223     }
224 #if __DEBUG__
225     char debugName[128];
226     uint64_t rMergesOrIo = 0;
227     uint64_t rwIos = 0;
228     uint64_t rTicksOrw = 0;
229     auto debugIoInfo = std::make_shared<DiskStats>();
230     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",
231                        &debugIoInfo->major_, &debugIoInfo->minor_, debugName, sizeof(debugName),
232                        &debugIoInfo->rSucc_, &rMergesOrIo, &rwIos, &rTicksOrw,
233                        &debugIoInfo->wSucc_, &debugIoInfo->wMerged_,
234                        &debugIoInfo->wSectors_, &debugIoInfo->timeOfWrite_,
235                        &debugIoInfo->ios_, &debugIoInfo->timeOfIo_, &debugIoInfo->weighted_,
236                        &debugIoInfo->dSucc_, &debugIoInfo->dMerged_,
237                        &debugIoInfo->dSectors_, &debugIoInfo->timeOfd_,
238                        &debugIoInfo->flushSucc_, &debugIoInfo->timeOfFlush_);
239     if (ret == NUM_SEVEN) {
240         debugIoInfo->rSectors_ = rMergesOrIo;
241         debugIoInfo->wSucc_ = rwIos;
242         debugIoInfo->wSectors_ = rTicksOrw;
243     } else {
244         debugIoInfo->rMerged_  = rMergesOrIo;
245         debugIoInfo->rSectors_ = rwIos;
246         debugIoInfo->timeOfRead_ = rTicksOrw;
247     }
248     debugIoInfo->deviceName_ = std::string(name);
249     ioDatas_.push_back(debugIoInfo);
250 #endif
251 
252     return false;
253 }
254 
ParseIoStatsEx()255 bool IoStats::ParseIoStatsEx()
256 {
257     return true;
258 }
259 
PutPluginStatsData(StatsData * pluginStats)260 bool IoStats::PutPluginStatsData(StatsData* pluginStats)
261 {
262     PutCpuStatsData(pluginStats);
263     if (type_ == DiskioConfig::IO_REPORT) {
264         PutIoStatsData(pluginStats);
265     } else if (type_ == DiskioConfig::IO_REPORT_EX) {
266         ParseIoStatsEx();
267     }
268     return true;
269 }
270 
PutCpuStatsData(StatsData * pluginStats)271 uint32_t IoStats::PutCpuStatsData(StatsData* pluginStats)
272 {
273     std::unique_lock<std::mutex> lock(mutex_);
274     if (cpuDatas_.empty()) {
275         return 0;
276     }
277 
278     uint32_t count = 0;
279     while (cpuDatas_.size() > 0) {
280         auto cpuData = cpuDatas_.front();
281         auto* cpuInfo = pluginStats->add_cpuinfo();
282         CalcCpuStats(cpuData, cpuInfo);
283         cpuDatas_.pop_front();
284         count++;
285     }
286     lock.unlock();
287     return count;
288 }
289 
CalcCpuStats(const CpuDatasPtr & cpuData,CpuStats * cpuInfo)290 void IoStats::CalcCpuStats(const CpuDatasPtr& cpuData, CpuStats* cpuInfo)
291 {
292     auto totalTime = cpuData->GetTotalTime();
293     cpuInfo->set_name(cpuData->name_);
294     cpuInfo->set_cpu_user(KeepTowDigits(cpuData->user_, totalTime));
295     cpuInfo->set_cpu_nice(KeepTowDigits(cpuData->nice_, totalTime));
296     cpuInfo->set_cpu_iowait(KeepTowDigits(cpuData->iowait_, totalTime));
297     cpuInfo->set_cpu_steal(KeepTowDigits(cpuData->steal_, totalTime));
298 
299     cpuInfo->set_cpu_sys(KeepTowDigits(cpuData->system_ + cpuData->softirq_ + cpuData->hardirq_, totalTime));
300     cpuInfo->set_cpu_idle(KeepTowDigits(cpuData->idle_, totalTime));
301 }
302 
KeepTowDigits(const uint64_t & data,uint64_t div)303 double IoStats::KeepTowDigits(const uint64_t& data, uint64_t div)
304 {
305     double result = 0.00;
306     if (data <= 0 || div == 0) {
307         return result;
308     }
309     double ddiv = div;
310     if (ddiv != NUM_TWO) {
311         ddiv = div * NUM_ZERO_POINTZEROONE;
312     }
313     result = static_cast<double>(data) / ddiv;
314     return result;
315 }
316 
PutIoStatsData(StatsData * pluginStats)317 uint32_t IoStats::PutIoStatsData(StatsData* pluginStats)
318 {
319     std::unique_lock<std::mutex> lock(mutex_);
320     if (ioDatas_.empty()) {
321         return 0;
322     }
323 
324     uint32_t count = 0;
325     while (ioDatas_.size() > 0) {
326         auto ioData = ioDatas_.front();
327         auto* ioInfo = pluginStats->add_statsinfo();
328         CalcIoStats(ioData, ioInfo);
329         ioDatas_.pop_front();
330         count++;
331     }
332     lock.unlock();
333     return count;
334 }
335 
CalcIoStats(const DiskDatasPtr & ioData,IoStatData * ioInfo)336 void IoStats::CalcIoStats(const DiskDatasPtr& ioData, IoStatData* ioInfo)
337 {
338     ioInfo->set_name(ioData->deviceName_);
339     // (成功完成读的总次数 + 写 + 丢弃) / sysTime_
340     ioInfo->set_ios_per_sec(KeepTowDigits(ioData->rSucc_ + ioData->wSucc_ + ioData->dSucc_, sysTime_));
341 
342     // 读扇区的次数 / sysTime_
343     ioInfo->set_rd_per_sec(KeepTowDigits(KeepTowDigits(ioData->rSectors_, sysTime_), NUM_TWO));
344     ioInfo->set_wr_per_sec(KeepTowDigits(KeepTowDigits(ioData->wSectors_, sysTime_), NUM_TWO));
345     ioInfo->set_dc_per_sec(KeepTowDigits(KeepTowDigits(ioData->dSectors_, sysTime_), NUM_TWO));
346 
347     // 读扇区的次数
348     ioInfo->set_rd_kb(KeepTowDigits(ioData->rSectors_, NUM_TWO));
349     ioInfo->set_wr_kb(KeepTowDigits(ioData->wSectors_, NUM_TWO));
350     ioInfo->set_dc_kb(KeepTowDigits(ioData->dSectors_, NUM_TWO));
351 }
352 
StringToL(const char * word,long & value)353 bool IoStats::StringToL(const char* word, long& value)
354 {
355     char* end = nullptr;
356     errno = 0;
357     value = strtol(word, &end, DEC_BASE);
358     if ((errno == ERANGE && (value == LONG_MAX)) || (errno != 0 && value == 0)) {
359         return false;
360     } else if (end == word && (*word >= '0' && *word <= '9')) {
361         return false;
362     }
363 
364     return true;
365 }
366 
FindFirstNum(char ** p)367 bool IoStats::FindFirstNum(char** p)
368 {
369     CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
370     while (**p > '9' || **p < '0') {
371         if (**p == '\0' || **p == '\n') {
372             return false;
373         }
374         (*p)++;
375     }
376     return true;
377 }
378 
RemoveSpaces(char ** p)379 bool IoStats::RemoveSpaces(char** p)
380 {
381     CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
382     if (**p == '\0' || **p == '\n') {
383         return false;
384     }
385     while (**p == ' ') {
386         (*p)++;
387         if (**p == '\0' || **p == '\n') {
388             return false;
389         }
390     }
391     return true;
392 }
393 
FindFirstSpace(char ** p)394 bool IoStats::FindFirstSpace(char** p)
395 {
396     CHECK_NOTNULL(*p, false, "IoStats:%s", __func__);
397     while (**p != ' ') {
398         if (**p == '\0' || **p == '\n') {
399             return false;
400         }
401         (*p)++;
402     }
403     return true;
404 }
405 
ParseLineFields(const std::string & line,std::string & name)406 uint32_t IoStats::ParseLineFields(const std::string& line, std::string& name)
407 {
408     uint64_t num;
409     uint32_t count = 0;
410     char* end = nullptr;
411     char* pTmp = const_cast<char*>(line.c_str());
412 
413     fields_.clear();
414     while (pTmp != nullptr && *pTmp != '\n') {
415         CHECK_TRUE(RemoveSpaces(&pTmp), count, "%s: RemoveSpaces failed!", __func__);
416         if (*pTmp >= 'a' && *pTmp <= 'z') {
417             char field[64];
418             int len = 0;
419             int ret = sscanf_s(pTmp, "%63s %n", field, sizeof(field), &len);
420             if (ret == 1 && *field) {
421                 name = std::string(field, strlen(field));
422                 pTmp += len;
423             }
424         }
425         CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
426         num = strtoull(pTmp, &end, DEC_BASE);
427         CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
428         fields_.push_back(num);
429         pTmp = end;
430         count++;
431     }
432     return count;
433 }
434 
ParseLineFields(const std::string & line)435 uint32_t IoStats::ParseLineFields(const std::string& line)
436 {
437     uint64_t num;
438     uint32_t count = 0;
439     char* end = nullptr;
440     char* pTmp = const_cast<char*>(line.c_str());
441 
442     while (pTmp != nullptr && *pTmp != '\n') {
443         CHECK_TRUE(FindFirstNum(&pTmp), count, "%s: FindFirstNum failed", __func__);
444         num = static_cast<uint32_t>(strtoull(pTmp, &end, DEC_BASE));
445         CHECK_TRUE(num >= 0, count, "%s:strtoull failed", __func__);
446         fields_.push_back(num);
447         pTmp = end;
448         count++;
449     }
450     return count;
451 }