Home | History | Annotate | Download | only in storaged
      1 /*
      2  * Copyright (C) 2016 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 #define LOG_TAG "storaged"
     18 
     19 #include <dirent.h>
     20 #include <fcntl.h>
     21 #include <linux/time.h>
     22 #include <stdint.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <sys/stat.h>
     27 #include <time.h>
     28 #include <unistd.h>
     29 
     30 #include <iomanip>
     31 #include <sstream>
     32 #include <string>
     33 #include <unordered_map>
     34 
     35 #include <android-base/file.h>
     36 #include <android-base/logging.h>
     37 #include <android-base/stringprintf.h>
     38 #include <android-base/strings.h>
     39 #include <log/log_event_list.h>
     40 
     41 #include <storaged.h>
     42 #include <storaged_utils.h>
     43 
     44 bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
     45     // Get time
     46     struct timespec ts;
     47     // Use monotonic to exclude suspend time so that we measure IO bytes/sec
     48     // when system is running.
     49     int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
     50     if (ret < 0) {
     51         PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
     52         return false;
     53     }
     54 
     55     std::string buffer;
     56     if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
     57         PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
     58         return false;
     59     }
     60 
     61     // Regular diskstats entries
     62     std::stringstream ss(buffer);
     63     for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
     64         ss >> *((uint64_t*)stats + i);
     65     }
     66     // Other entries
     67     stats->start_time = 0;
     68     stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
     69         ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
     70     stats->counter = 1;
     71     stats->io_avg = (double)stats->io_in_flight;
     72     return true;
     73 }
     74 
     75 struct disk_perf get_disk_perf(struct disk_stats* stats) {
     76     struct disk_perf perf;
     77     memset(&perf, 0, sizeof(struct disk_perf));  // initialize
     78 
     79     if (stats->io_ticks) {
     80         if (stats->read_ticks) {
     81             unsigned long long divisor = stats->read_ticks * stats->io_ticks;
     82             perf.read_perf = ((unsigned long long)SECTOR_SIZE *
     83                                         stats->read_sectors *
     84                                         stats->io_in_queue +
     85                                         (divisor >> 1)) /
     86                                             divisor;
     87             perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
     88                                         stats->read_ios *
     89                                         stats->io_in_queue +
     90                                         (divisor >> 1)) /
     91                                             divisor;
     92         }
     93         if (stats->write_ticks) {
     94             unsigned long long divisor = stats->write_ticks * stats->io_ticks;
     95                         perf.write_perf = ((unsigned long long)SECTOR_SIZE *
     96                                                     stats->write_sectors *
     97                                                     stats->io_in_queue +
     98                                                     (divisor >> 1)) /
     99                                                         divisor;
    100                         perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
    101                                                     stats->write_ios *
    102                                                     stats->io_in_queue +
    103                                                     (divisor >> 1)) /
    104                                                         divisor;
    105         }
    106         perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
    107                                 stats->io_ticks;
    108     }
    109     return perf;
    110 }
    111 
    112 struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
    113     struct disk_stats inc;
    114     for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
    115         if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
    116             continue;
    117         }
    118 
    119         *((uint64_t*)&inc + i) =
    120                 *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
    121     }
    122     // io_in_flight is exception
    123     inc.io_in_flight = curr->io_in_flight;
    124 
    125     inc.start_time = prev->end_time;
    126     inc.end_time = curr->end_time;
    127     inc.io_avg = curr->io_avg;
    128     inc.counter = 1;
    129 
    130     return inc;
    131 }
    132 
    133 // Add src to dst
    134 void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
    135     if (dst->end_time != 0 && dst->end_time != src->start_time) {
    136         LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
    137             << " are added. dst end with " << dst->end_time
    138             << ", src start with " << src->start_time;
    139     }
    140 
    141     for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
    142         if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
    143             continue;
    144         }
    145 
    146         *((uint64_t*)dst + i) += *((uint64_t*)src + i);
    147     }
    148 
    149     dst->io_in_flight = src->io_in_flight;
    150     if (dst->counter + src->counter) {
    151         dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
    152                         (dst->counter + src->counter);
    153     }
    154     dst->counter += src->counter;
    155     dst->end_time = src->end_time;
    156     if (dst->start_time == 0) {
    157         dst->start_time = src->start_time;
    158     }
    159 }
    160 
    161 static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
    162     // Compare background I/O first.
    163     for (int i = UID_STATS - 1; i >= 0; i--) {
    164         uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
    165         uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes;
    166         uint64_t l_chars = l.io[i].rchar + l.io[i].wchar;
    167         uint64_t r_chars = r.io[i].rchar + r.io[i].wchar;
    168 
    169         if (l_bytes != r_bytes) {
    170             return l_bytes > r_bytes;
    171         }
    172         if (l_chars != r_chars) {
    173             return l_chars > r_chars;
    174         }
    175     }
    176 
    177     return l.name < r.name;
    178 }
    179 
    180 void sort_running_uids_info(std::vector<struct uid_info> &uids) {
    181     std::sort(uids.begin(), uids.end(), cmp_uid_info);
    182 }
    183 
    184 // Logging functions
    185 void log_console_running_uids_info(std::vector<struct uid_info> uids) {
    186     printf("name/uid fg_rchar fg_wchar fg_rbytes fg_wbytes "
    187            "bg_rchar bg_wchar bg_rbytes bg_wbytes fg_fsync bg_fsync\n");
    188 
    189     for (const auto& uid : uids) {
    190         printf("%s %ju %ju %ju %ju %ju %ju %ju %ju %ju %ju\n", uid.name.c_str(),
    191             uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes,
    192             uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes,
    193             uid.io[0].fsync, uid.io[1].fsync);
    194     }
    195     fflush(stdout);
    196 }
    197 
    198 #if DEBUG
    199 void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
    200     // skip if the input structure are all zeros
    201     if (perf == NULL) return;
    202     struct disk_perf zero_cmp;
    203     memset(&zero_cmp, 0, sizeof(zero_cmp));
    204     if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
    205 
    206     LOG_TO(SYSTEM, INFO) << "perf(ios) " << type
    207               << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)"
    208               << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)"
    209               << " q:" << perf->queue;
    210 }
    211 #else
    212 void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {}
    213 #endif
    214 
    215 void log_event_disk_stats(struct disk_stats* stats, const char* type) {
    216     // skip if the input structure are all zeros
    217     if (stats == NULL) return;
    218     struct disk_stats zero_cmp;
    219     memset(&zero_cmp, 0, sizeof(zero_cmp));
    220     // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
    221     if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
    222 
    223     android_log_event_list(EVENTLOGTAG_DISKSTATS)
    224         << type << stats->start_time << stats->end_time
    225         << stats->read_ios << stats->read_merges
    226         << stats->read_sectors << stats->read_ticks
    227         << stats->write_ios << stats->write_merges
    228         << stats->write_sectors << stats->write_ticks
    229         << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
    230         << LOG_ID_EVENTS;
    231 }
    232 
    233