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 16 #ifndef IO_STATS_H 17 #define IO_STATS_H 18 19 #include <deque> 20 #include <array> 21 #include <cinttypes> 22 #include <cstdio> 23 #include <fstream> 24 #include <inttypes.h> 25 #include <iostream> 26 #include <memory> 27 #include <string> 28 #include <sys/mman.h> 29 30 #include "diskio_plugin_config.pb.h" 31 #include "diskio_plugin_result.pb.h" 32 #include "logging.h" 33 34 constexpr int NUM_TWO = 2; 35 36 class ProcStats { 37 public: 38 std::string name_; 39 uint64_t user_; 40 uint64_t nice_; 41 uint64_t system_; 42 uint64_t idle_; 43 uint64_t iowait_; 44 uint64_t steal_; 45 uint64_t hardirq_; 46 uint64_t softirq_; 47 uint64_t guest_; 48 uint64_t guestNice_; 49 ProcStats()50 ProcStats() 51 : name_(""), 52 user_(0), 53 nice_(0), 54 system_(0), 55 idle_(0), 56 iowait_(0), 57 steal_(0), 58 hardirq_(0), 59 softirq_(0), 60 guest_(0), 61 guestNice_(0) 62 { 63 } 64 ~ProcStats()65 ~ProcStats() {} 66 GetTotalTime()67 uint64_t GetTotalTime() 68 { 69 return user_ + nice_ + system_ + idle_ + iowait_ + steal_ + hardirq_ + softirq_; 70 } 71 }; 72 73 class DiskStats { 74 public: 75 std::string deviceName_; 76 uint64_t major_; 77 uint64_t minor_; 78 79 uint64_t rSucc_; // 成功完成读的总次数 rd_ios 80 uint64_t rMerged_; // 合并读次数 rd_merges 81 uint64_t rSectors_; // 读扇区的次数 rd_sectors 82 uint64_t timeOfRead_; // 读花的时间(ms) rd_ticks 83 84 uint64_t wSucc_; // 成功完成写的总次数 wr_ios 85 uint64_t wMerged_; // 合并写次数 wr_merges 86 uint64_t wSectors_; // 写扇区的次数 wr_sectors 87 uint64_t timeOfWrite_; // 写花的时间(ms) wr_ticks 88 89 uint64_t dSucc_; 90 uint64_t dMerged_; 91 uint64_t dSectors_; 92 uint64_t timeOfd_; 93 94 uint64_t flushSucc_; 95 uint64_t timeOfFlush_; 96 97 uint64_t ios_; // I/O的当前进度 ios_pgr 98 uint64_t timeOfIo_; // I/O操作上的毫秒数 tot_ticks ? 99 uint64_t weighted_; // 输入/输出操作花费的加权毫秒数 rq_ticks ? 100 DiskStats()101 DiskStats() 102 : deviceName_(""), 103 major_(0), 104 minor_(0), 105 rSucc_(0), 106 rMerged_(0), 107 rSectors_(0), 108 timeOfRead_(0), 109 wSucc_(0), 110 wMerged_(0), 111 wSectors_(0), 112 timeOfWrite_(0), 113 dSucc_(0), 114 dMerged_(0), 115 dSectors_(0), 116 timeOfd_(0), 117 flushSucc_(0), 118 timeOfFlush_(0), 119 ios_(0), 120 timeOfIo_(0), 121 weighted_(0) 122 { 123 } 124 ~DiskStats()125 ~DiskStats() {} 126 }; 127 128 using CpuDatasPtr = std::shared_ptr<ProcStats>; 129 using DiskDatasPtr = std::shared_ptr<DiskStats>; 130 class IoStats { 131 public: 132 IoStats(DiskioConfig::IoReportType type = DiskioConfig::UNSPECIFIED); ~IoStats()133 ~IoStats() {} 134 bool GetIoData(); 135 PutPluginStatsData(T & pluginStatsData)136 template <typename T> bool PutPluginStatsData(T& pluginStatsData) 137 { 138 PutCpuStatsData(pluginStatsData); 139 if (type_ == DiskioConfig::IO_REPORT) { 140 PutIoStatsData(pluginStatsData); 141 } else if (type_ == DiskioConfig::IO_REPORT_EX) { 142 ParseIoStatsEx(); 143 } 144 return true; 145 } 146 147 private: 148 bool ParseCpuStats(); 149 bool GetCpuStats(std::string& line); 150 bool ParseIoStats(); 151 bool GetIoStats(std::string& line); 152 PutCpuStatsData(T & pluginStatsData)153 template <typename T> uint32_t PutCpuStatsData(T& pluginStatsData) 154 { 155 std::unique_lock<std::mutex> lock(mutex_); 156 if (cpuDatas_.empty()) { 157 return 0; 158 } 159 160 uint32_t count = 0; 161 while (cpuDatas_.size() > 0) { 162 auto cpuData = cpuDatas_.front(); 163 auto* cpuInfo = pluginStatsData.add_cpuinfo(); 164 CalcCpuStats(cpuData, *cpuInfo); 165 cpuDatas_.pop_front(); 166 count++; 167 } 168 lock.unlock(); 169 return count; 170 } 171 CalcCpuStats(const CpuDatasPtr & cpuData,T & cpuStatsInfo)172 template <typename T> void CalcCpuStats(const CpuDatasPtr& cpuData, T& cpuStatsInfo) 173 { 174 auto totalTime = cpuData->GetTotalTime(); 175 cpuStatsInfo.set_name(cpuData->name_); 176 cpuStatsInfo.set_cpu_user(KeepTowDigits(cpuData->user_, totalTime)); 177 cpuStatsInfo.set_cpu_nice(KeepTowDigits(cpuData->nice_, totalTime)); 178 cpuStatsInfo.set_cpu_iowait(KeepTowDigits(cpuData->iowait_, totalTime)); 179 cpuStatsInfo.set_cpu_steal(KeepTowDigits(cpuData->steal_, totalTime)); 180 181 cpuStatsInfo.set_cpu_sys(KeepTowDigits(cpuData->system_ + cpuData->softirq_ + cpuData->hardirq_, totalTime)); 182 cpuStatsInfo.set_cpu_idle(KeepTowDigits(cpuData->idle_, totalTime)); 183 } 184 185 double KeepTowDigits(const uint64_t& data, uint64_t div); 186 PutIoStatsData(T & pluginStatsData)187 template <typename T> uint32_t PutIoStatsData(T& pluginStatsData) 188 { 189 std::unique_lock<std::mutex> lock(mutex_); 190 if (ioDatas_.empty()) { 191 return 0; 192 } 193 194 uint32_t count = 0; 195 while (ioDatas_.size() > 0) { 196 auto ioData = ioDatas_.front(); 197 auto* ioInfo = pluginStatsData.add_statsinfo(); 198 CalcIoStats(ioData, *ioInfo); 199 ioDatas_.pop_front(); 200 count++; 201 } 202 lock.unlock(); 203 return count; 204 } 205 CalcIoStats(const DiskDatasPtr & ioData,T & ioStatDataInfo)206 template <typename T> void CalcIoStats(const DiskDatasPtr& ioData, T& ioStatDataInfo) 207 { 208 ioStatDataInfo.set_name(ioData->deviceName_); 209 // (成功完成读的总次数 + 写 + 丢弃) / sysTime_ 210 ioStatDataInfo.set_ios_per_sec(KeepTowDigits(ioData->rSucc_ + ioData->wSucc_ + ioData->dSucc_, sysTime_)); 211 212 // 读扇区的次数 / sysTime_ 213 ioStatDataInfo.set_rd_per_sec(KeepTowDigits(KeepTowDigits(ioData->rSectors_, sysTime_), NUM_TWO)); 214 ioStatDataInfo.set_wr_per_sec(KeepTowDigits(KeepTowDigits(ioData->wSectors_, sysTime_), NUM_TWO)); 215 ioStatDataInfo.set_dc_per_sec(KeepTowDigits(KeepTowDigits(ioData->dSectors_, sysTime_), NUM_TWO)); 216 217 // 读扇区的次数 218 ioStatDataInfo.set_rd_kb(KeepTowDigits(ioData->rSectors_, NUM_TWO)); 219 ioStatDataInfo.set_wr_kb(KeepTowDigits(ioData->wSectors_, NUM_TWO)); 220 ioStatDataInfo.set_dc_kb(KeepTowDigits(ioData->dSectors_, NUM_TWO)); 221 } 222 uint32_t OutputCpuData(); 223 bool OutputIoData(); 224 uint64_t GetSystime(); 225 bool ParseIoStatsEx(); 226 bool FindFirstNum(char** p); 227 bool RemoveSpaces(char** p); 228 uint32_t ParseLineFields(const std::string& line); 229 uint32_t ParseLineFields(const std::string& line, std::string& name); 230 231 private: 232 std::mutex mutex_; 233 DiskioConfig::IoReportType type_; 234 uint64_t sysTime_; 235 std::deque<CpuDatasPtr> cpuDatas_; 236 std::deque<DiskDatasPtr> ioDatas_; 237 std::vector<uint64_t> fields_; 238 }; 239 240 #endif // #ifndef IO_STATS_H 241