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 <stdlib.h>
     20 #include <time.h>
     21 #include <unistd.h>
     22 
     23 #include <android-base/logging.h>
     24 #include <batteryservice/BatteryServiceConstants.h>
     25 #include <batteryservice/IBatteryPropertiesRegistrar.h>
     26 #include <binder/IPCThreadState.h>
     27 #include <binder/IServiceManager.h>
     28 #include <cutils/properties.h>
     29 #include <log/log.h>
     30 
     31 #include <storaged.h>
     32 #include <storaged_utils.h>
     33 
     34 /* disk_stats_publisher */
     35 void disk_stats_publisher::publish(void) {
     36     // Logging
     37     struct disk_perf perf = get_disk_perf(&mAccumulate);
     38     log_debug_disk_perf(&perf, "regular");
     39     log_event_disk_stats(&mAccumulate, "regular");
     40     // Reset global structures
     41     memset(&mAccumulate, 0, sizeof(struct disk_stats));
     42 }
     43 
     44 void disk_stats_publisher::update(void) {
     45     struct disk_stats curr;
     46     if (parse_disk_stats(DISK_STATS_PATH, &curr)) {
     47         struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr);
     48         add_disk_stats(&inc, &mAccumulate);
     49 #ifdef DEBUG
     50 //            log_kernel_disk_stats(&mPrevious, "prev stats");
     51 //            log_kernel_disk_stats(&curr, "curr stats");
     52 //            log_kernel_disk_stats(&inc, "inc stats");
     53 //            log_kernel_disk_stats(&mAccumulate, "accumulated stats");
     54 #endif
     55         mPrevious = curr;
     56     }
     57 }
     58 
     59 /* disk_stats_monitor */
     60 void disk_stats_monitor::update_mean() {
     61     CHECK(mValid);
     62     mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
     63     mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
     64     mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
     65     mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
     66     mMean.queue = (uint32_t)mStats.queue.get_mean();
     67 }
     68 
     69 void disk_stats_monitor::update_std() {
     70     CHECK(mValid);
     71     mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
     72     mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
     73     mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
     74     mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
     75     mStd.queue = (uint32_t)mStats.queue.get_std();
     76 }
     77 
     78 void disk_stats_monitor::add(struct disk_perf* perf) {
     79     mStats.read_perf.add(perf->read_perf);
     80     mStats.read_ios.add(perf->read_ios);
     81     mStats.write_perf.add(perf->write_perf);
     82     mStats.write_ios.add(perf->write_ios);
     83     mStats.queue.add(perf->queue);
     84 }
     85 
     86 void disk_stats_monitor::evict(struct disk_perf* perf) {
     87     mStats.read_perf.evict(perf->read_perf);
     88     mStats.read_ios.evict(perf->read_ios);
     89     mStats.write_perf.evict(perf->write_perf);
     90     mStats.write_ios.evict(perf->write_ios);
     91     mStats.queue.evict(perf->queue);
     92 }
     93 
     94 bool disk_stats_monitor::detect(struct disk_perf* perf) {
     95     return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
     96             ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
     97             ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
     98 }
     99 
    100 void disk_stats_monitor::update(struct disk_stats* stats) {
    101     struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats);
    102     struct disk_perf perf = get_disk_perf(&inc);
    103     // Update internal data structures
    104     if (LIKELY(mValid)) {
    105         CHECK_EQ(mBuffer.size(), mWindow);
    106 
    107         if (UNLIKELY(detect(&perf))) {
    108             mStall = true;
    109             add_disk_stats(&inc, &mAccumulate);
    110             log_debug_disk_perf(&mMean, "stalled_mean");
    111             log_debug_disk_perf(&mStd, "stalled_std");
    112         } else {
    113             if (mStall) {
    114                 struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
    115                 log_debug_disk_perf(&acc_perf, "stalled");
    116                 log_event_disk_stats(&mAccumulate, "stalled");
    117                 mStall = false;
    118                 memset(&mAccumulate, 0, sizeof(mAccumulate));
    119             }
    120         }
    121 
    122         evict(&mBuffer.front());
    123         mBuffer.pop();
    124         add(&perf);
    125         mBuffer.push(perf);
    126 
    127         update_mean();
    128         update_std();
    129 
    130     } else { /* mValid == false */
    131         CHECK_LT(mBuffer.size(), mWindow);
    132         add(&perf);
    133         mBuffer.push(perf);
    134         if (mBuffer.size() == mWindow) {
    135             mValid = true;
    136             update_mean();
    137             update_std();
    138         }
    139     }
    140 
    141     mPrevious = *stats;
    142 }
    143 
    144 void disk_stats_monitor::update(void) {
    145     struct disk_stats curr;
    146     if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) {
    147         update(&curr);
    148     }
    149 }
    150 
    151 static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
    152     sp<IServiceManager> sm = defaultServiceManager();
    153     if (sm == NULL) return NULL;
    154 
    155     sp<IBinder> binder = sm->getService(String16("batteryproperties"));
    156     if (binder == NULL) return NULL;
    157 
    158     sp<IBatteryPropertiesRegistrar> battery_properties =
    159         interface_cast<IBatteryPropertiesRegistrar>(binder);
    160 
    161     return battery_properties;
    162 }
    163 
    164 static inline charger_stat_t is_charger_on(int64_t prop) {
    165     return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
    166         CHARGER_ON : CHARGER_OFF;
    167 }
    168 
    169 void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
    170     mUidm.set_charger_state(is_charger_on(props.batteryStatus));
    171 }
    172 
    173 void storaged_t::init_battery_service() {
    174     if (!mConfig.proc_uid_io_available)
    175         return;
    176 
    177     battery_properties = get_battery_properties_service();
    178     if (battery_properties == NULL) {
    179         LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
    180         return;
    181     }
    182 
    183     struct BatteryProperty val;
    184     battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
    185     mUidm.init(is_charger_on(val.valueInt64));
    186 
    187     // register listener after init uid_monitor
    188     battery_properties->registerListener(this);
    189     IInterface::asBinder(battery_properties)->linkToDeath(this);
    190 }
    191 
    192 void storaged_t::binderDied(const wp<IBinder>& who) {
    193     if (battery_properties != NULL &&
    194         IInterface::asBinder(battery_properties) == who) {
    195         LOG_TO(SYSTEM, ERROR) << "batteryproperties service died, exiting";
    196         IPCThreadState::self()->stopProcess();
    197         exit(1);
    198     } else {
    199         LOG_TO(SYSTEM, ERROR) << "unknown service died";
    200     }
    201 }
    202 
    203 /* storaged_t */
    204 storaged_t::storaged_t(void) {
    205     if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
    206         mConfig.diskstats_available = false;
    207     } else {
    208         mConfig.diskstats_available = true;
    209     }
    210 
    211     mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0);
    212 
    213     mConfig.periodic_chores_interval_unit =
    214         property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
    215 
    216     mConfig.event_time_check_usec =
    217         property_get_int32("ro.storaged.event.perf_check", 0);
    218 
    219     mConfig.periodic_chores_interval_disk_stats_publish =
    220         property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
    221 
    222     mConfig.periodic_chores_interval_uid_io =
    223         property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
    224 
    225     mStarttime = time(NULL);
    226 }
    227 
    228 void storaged_t::event(void) {
    229     if (mConfig.diskstats_available) {
    230         mDiskStats.update();
    231         mDsm.update();
    232         if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
    233             mDiskStats.publish();
    234         }
    235     }
    236 
    237     if (mConfig.proc_uid_io_available && mTimer &&
    238             (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
    239          mUidm.report();
    240     }
    241 
    242     mTimer += mConfig.periodic_chores_interval_unit;
    243 }
    244 
    245 void storaged_t::event_checked(void) {
    246     struct timespec start_ts, end_ts;
    247     bool check_time = true;
    248 
    249     if (mConfig.event_time_check_usec &&
    250         clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) {
    251         check_time = false;
    252         static time_t state_a;
    253         IF_ALOG_RATELIMIT_LOCAL(300, &state_a) {
    254             PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
    255         }
    256     }
    257 
    258     event();
    259 
    260     if (mConfig.event_time_check_usec && check_time) {
    261         if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) {
    262             static time_t state_b;
    263             IF_ALOG_RATELIMIT_LOCAL(300, &state_b) {
    264                 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
    265             }
    266             return;
    267         }
    268         int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC +
    269                        (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC;
    270         if (cost > mConfig.event_time_check_usec) {
    271             LOG_TO(SYSTEM, ERROR)
    272                 << "event loop spent " << cost << " usec, threshold "
    273                 << mConfig.event_time_check_usec << " usec";
    274         }
    275     }
    276 }
    277