Home | History | Annotate | Download | only in include
      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 <android/hardware/health/2.0/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 
     55     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
    111     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:
    123     stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
    124     ~stream_stats() {};
    125     double get_mean() {
    126         return mSum / mCnt;
    127     }
    128     double get_std() {
    129         return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
    130     }
    131     void add(uint32_t num) {
    132         mSum += (double)num;
    133         mSquareSum += (double)num * (double)num;
    134         mCnt++;
    135     }
    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     android::sp<android::hardware::health::V2_0::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 android::sp<android::hardware::health::V2_0::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 : nullptr))),
    184         mPrevious(),
    185         mAccumulate(),
    186         mAccumulate_pub(),
    187         mStall(false),
    188         mValid(false),
    189         mWindow(window_size),
    190         mSigma(sigma),
    191         mMean(),
    192         mStd(),
    193         mHealth(healthService) {}
    194   bool enabled() { return mHealth != nullptr || DISK_STATS_PATH != nullptr; }
    195   void update(void);
    196   void publish(void);
    197 };
    198 
    199 #endif /* _STORAGED_DISKSTATS_H_ */
    200