1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _STORAGED_DISKSTATS_H_ 18 #define _STORAGED_DISKSTATS_H_ 19 20 #include <stdint.h> 21 22 #include <aidl/android/hardware/health/IHealth.h> 23 24 // number of attributes diskstats has 25 #define DISK_STATS_SIZE ( 11 ) 26 27 #define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" 28 #define SDA_DISK_STATS_PATH "/sys/block/sda/stat" 29 30 struct disk_stats { 31 /* It will be extremely unlikely for any of the following entries to overflow. 32 * For read_bytes(which will be greater than any of the following entries), it 33 * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which 34 * is the peak memory transfer rate for current memory. 35 * The diskstats entries (first 11) need to be at top in this structure _after_ 36 * compiler's optimization. 37 */ 38 uint64_t read_ios; // number of read I/Os processed 39 uint64_t read_merges; // number of read I/Os merged with in-queue I/Os 40 uint64_t read_sectors; // number of sectors read 41 uint64_t read_ticks; // total wait time for read requests 42 uint64_t write_ios; // number of write I/Os processed 43 uint64_t write_merges; // number of write I/Os merged with in-queue I/Os 44 uint64_t write_sectors; // number of sectors written 45 uint64_t write_ticks; // total wait time for write requests 46 uint64_t io_in_flight; // number of I/Os currently in flight 47 uint64_t io_ticks; // total time this block device has been active 48 uint64_t io_in_queue; // total wait time for all requests 49 50 uint64_t start_time; // monotonic time accounting starts 51 uint64_t end_time; // monotonic time accounting ends 52 uint32_t counter; // private counter for accumulate calculations 53 double io_avg; // average io_in_flight for accumulate calculations 54 is_zerodisk_stats55 bool is_zero() { 56 return read_ios == 0 && write_ios == 0 && 57 io_in_flight == 0 && io_ticks == 0 && io_in_queue == 0; 58 } 59 60 friend disk_stats operator- (disk_stats curr, const disk_stats& prev) { 61 curr.read_ios -= prev.read_ios; 62 curr.read_merges -= prev.read_merges; 63 curr.read_sectors -= prev.read_sectors; 64 curr.read_ticks -= prev.read_ticks; 65 curr.write_ios -= prev.write_ios; 66 curr.write_merges -= prev.write_merges; 67 curr.write_sectors -= prev.write_sectors; 68 curr.write_ticks -= prev.write_ticks; 69 /* skips io_in_flight, use current value */ 70 curr.io_ticks -= prev.io_ticks; 71 curr.io_in_queue -= prev.io_in_queue; 72 return curr; 73 } 74 75 friend bool operator== (const disk_stats& a, const disk_stats& b) { 76 return a.read_ios == b.read_ios && 77 a.read_merges == b.read_merges && 78 a.read_sectors == b.read_sectors && 79 a.read_ticks == b.read_ticks && 80 a.write_ios == b.write_ios && 81 a.write_merges == b.write_merges && 82 a.write_sectors == b.write_sectors && 83 a.write_ticks == b.write_ticks && 84 /* skips io_in_flight */ 85 a.io_ticks == b.io_ticks && 86 a.io_in_queue == b.io_in_queue; 87 } 88 89 disk_stats& operator+= (const disk_stats& stats) { 90 read_ios += stats.read_ios; 91 read_merges += stats.read_merges; 92 read_sectors += stats.read_sectors; 93 read_ticks += stats.read_ticks; 94 write_ios += stats.write_ios; 95 write_merges += stats.write_merges; 96 write_sectors += stats.write_sectors; 97 write_ticks += stats.write_ticks; 98 /* skips io_in_flight, use current value */ 99 io_ticks += stats.io_ticks; 100 io_in_queue += stats.io_in_queue; 101 return *this; 102 } 103 }; 104 105 struct disk_perf { 106 uint32_t read_perf; // read speed (kbytes/s) 107 uint32_t read_ios; // read I/Os per second 108 uint32_t write_perf; // write speed (kbytes/s) 109 uint32_t write_ios; // write I/Os per second 110 uint32_t queue; // I/Os in queue is_zerodisk_perf111 bool is_zero() { 112 return read_perf == 0 && read_ios == 0 && 113 write_perf == 0 && write_ios == 0 && queue == 0; 114 } 115 }; 116 117 class stream_stats { 118 private: 119 double mSum; 120 double mSquareSum; 121 uint32_t mCnt; 122 public: stream_stats()123 stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {}; ~stream_stats()124 ~stream_stats() {}; get_mean()125 double get_mean() { 126 return mSum / mCnt; 127 } get_std()128 double get_std() { 129 return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt)); 130 } add(uint32_t num)131 void add(uint32_t num) { 132 mSum += (double)num; 133 mSquareSum += (double)num * (double)num; 134 mCnt++; 135 } evict(uint32_t num)136 void evict(uint32_t num) { 137 if (mSum < num || mSquareSum < (double)num * (double)num) return; 138 mSum -= (double)num; 139 mSquareSum -= (double)num * (double)num; 140 mCnt--; 141 } 142 }; 143 144 class disk_stats_monitor { 145 private: 146 FRIEND_TEST(storaged_test, disk_stats_monitor); 147 const char* const DISK_STATS_PATH; 148 struct disk_stats mPrevious; 149 struct disk_stats mAccumulate; /* reset after stall */ 150 struct disk_stats mAccumulate_pub; /* reset after publish */ 151 bool mStall; 152 std::queue<struct disk_perf> mBuffer; 153 struct { 154 stream_stats read_perf; // read speed (bytes/s) 155 stream_stats read_ios; // read I/Os per second 156 stream_stats write_perf; // write speed (bytes/s) 157 stream_stats write_ios; // write I/O per second 158 stream_stats queue; // I/Os in queue 159 } mStats; 160 bool mValid; 161 const uint32_t mWindow; 162 const double mSigma; 163 struct disk_perf mMean; 164 struct disk_perf mStd; 165 std::shared_ptr<aidl::android::hardware::health::IHealth> mHealth; 166 167 void update_mean(); 168 void update_std(); 169 void add(struct disk_perf* perf); 170 void evict(struct disk_perf* perf); 171 bool detect(struct disk_perf* perf); 172 173 void update(struct disk_stats* stats); 174 175 public: 176 disk_stats_monitor(const std::shared_ptr<aidl::android::hardware::health::IHealth>& healthService, 177 uint32_t window_size = 5, double sigma = 1.0) 178 : DISK_STATS_PATH( 179 healthService != nullptr 180 ? nullptr 181 : (access(MMC_DISK_STATS_PATH, R_OK) == 0 182 ? MMC_DISK_STATS_PATH 183 : (access(SDA_DISK_STATS_PATH, R_OK) == 0 ? SDA_DISK_STATS_PATH 184 : nullptr))), 185 mPrevious(), 186 mAccumulate(), 187 mAccumulate_pub(), 188 mStall(false), 189 mValid(false), 190 mWindow(window_size), 191 mSigma(sigma), 192 mMean(), 193 mStd(), 194 mHealth(healthService) {} enabled()195 bool enabled() { return mHealth != nullptr || DISK_STATS_PATH != nullptr; } 196 void update(void); 197 void publish(void); 198 }; 199 200 #endif /* _STORAGED_DISKSTATS_H_ */ 201