From 5b962c6dbd305946ece05ffbd81d29c2ea211673 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Mon, 30 Jan 2017 14:48:38 -0800 Subject: storaged: account on/off charger per uid io usage Register a listener to batteryproperties service for charger stats change. Aggregate IO usage based on charger stats in a collection window. Bug: 33086174 Bug: 34198239 Change-Id: Ibe306c9c3ff8b8ada6be034aa8511268cb9a9b1c --- storaged/Android.mk | 23 ++-- storaged/include/storaged.h | 15 ++- storaged/include/storaged_uid_monitor.h | 76 ++++++++---- storaged/main.cpp | 2 + storaged/storaged.cpp | 47 +++++++- storaged/storaged_service.cpp | 26 ++-- storaged/storaged_uid_monitor.cpp | 204 ++++++++++++++++++-------------- storaged/storaged_utils.cpp | 2 +- 8 files changed, 252 insertions(+), 143 deletions(-) (limited to 'storaged') diff --git a/storaged/Android.mk b/storaged/Android.mk index 0e8b574e8..5abfb7ad5 100644 --- a/storaged/Android.mk +++ b/storaged/Android.mk @@ -2,22 +2,31 @@ LOCAL_PATH := $(call my-dir) -LIBSTORAGED_SHARED_LIBRARIES := libbinder libbase libutils libcutils liblog libsysutils libcap libpackagelistparser +LIBSTORAGED_SHARED_LIBRARIES := \ + libbinder \ + libbase \ + libutils \ + libcutils \ + liblog \ + libsysutils \ + libcap \ + libpackagelistparser \ + libbatteryservice \ include $(CLEAR_VARS) -LOCAL_SRC_FILES := storaged.cpp \ - storaged_service.cpp \ - storaged_utils.cpp \ - storaged_uid_monitor.cpp \ - EventLogTags.logtags +LOCAL_SRC_FILES := \ + storaged.cpp \ + storaged_service.cpp \ + storaged_utils.cpp \ + storaged_uid_monitor.cpp \ + EventLogTags.logtags LOCAL_MODULE := libstoraged LOCAL_CFLAGS := -Werror LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES) - include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index ba78882e1..7e5048fc4 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -26,8 +26,12 @@ #include #include +#include + #include "storaged_uid_monitor.h" +using namespace android; + #define FRIEND_TEST(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test @@ -268,7 +272,7 @@ struct storaged_config { int event_time_check_usec; // check how much cputime spent in event loop }; -class storaged_t { +class storaged_t : public BnBatteryPropertiesListener { private: time_t mTimer; storaged_config mConfig; @@ -294,11 +298,14 @@ public: } std::unordered_map get_uids(void) { - return mUidm.get_uids(); + return mUidm.get_uid_io_stats(); } - std::vector get_uid_events(int hours) { - return mUidm.dump_events(hours); + std::map> get_uid_records(int hours) { + return mUidm.dump(hours); } + + void init_battery_service(); + virtual void batteryPropertiesChanged(struct BatteryProperties props); }; // Eventlog tag diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index ac6a8bd9f..07e6daa3e 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -23,10 +23,22 @@ #include #include -enum { - UID_FOREGROUND = 0, - UID_BACKGROUND = 1, - UID_STATS_SIZE = 2 +enum uid_stat_t { + FOREGROUND = 0, + BACKGROUND = 1, + UID_STATS = 2 +}; + +enum charger_stat_t { + CHARGER_OFF = 0, + CHARGER_ON = 1, + CHARGER_STATS = 2 +}; + +enum io_type_t { + READ = 0, + WRITE = 1, + IO_TYPES = 2 }; struct uid_io_stats { @@ -39,39 +51,51 @@ struct uid_io_stats { struct uid_info { uint32_t uid; // user id std::string name; // package name - struct uid_io_stats io[UID_STATS_SIZE]; // [0]:foreground [1]:background + struct uid_io_stats io[UID_STATS]; // [0]:foreground [1]:background }; -struct uid_event { +struct uid_io_usage { + uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS]; +}; + +struct uid_record { std::string name; - uint64_t fg_read_bytes; - uint64_t fg_write_bytes; - uint64_t bg_read_bytes; - uint64_t bg_write_bytes; - uint64_t ts; - bool operator< (const struct uid_event& e) const { - return ts < e.ts; - } + struct uid_io_usage ios; }; class uid_monitor { private: - std::unordered_map last_uids; - std::vector events; - sem_t events_lock; - void set_last_uids(std::unordered_map&& uids, uint64_t ts); - int interval; // monitor interval in seconds - int threshold; // monitor threshold in bytes - uint64_t last_report_ts; // timestamp of last report in nsec + // last dump from /proc/uid_io/stats, uid -> uid_info + std::unordered_map last_uid_io_stats; + // current io usage for next report, app name -> uid_io_usage + std::unordered_map curr_io_stats; + // io usage records, timestamp -> vector of events + std::map> records; + // charger ON/OFF + charger_stat_t charger_stat; + // protects curr_io_stats, last_uid_io_stats, records and charger_stat + sem_t um_lock; + + // reads from /proc/uid_io/stats + std::unordered_map get_uid_io_stats_locked(); + // flushes curr_io_stats to records + void add_records_locked(uint64_t curr_ts); + // updates curr_io_stats and set last_uid_io_stats + void update_curr_io_stats_locked(); + public: uid_monitor(); ~uid_monitor(); - void set_periodic_chores_params(int intvl, int thold) { interval = intvl; threshold = thold; } - int get_periodic_chores_interval() { return interval; } - std::unordered_map get_uids(); + // called by storaged main thread + void init(charger_stat_t stat); + // called by storaged -u + std::unordered_map get_uid_io_stats(); + // called by dumpsys + std::map> dump(int hours); + // called by battery properties listener + void set_charger_state(charger_stat_t stat); + // called by storaged periodic_chore void report(); - void add_events(const std::vector& new_events, uint64_t curr_ts); - std::vector dump_events(int hours); }; #endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/main.cpp b/storaged/main.cpp index ee6a4c951..1103df22f 100644 --- a/storaged/main.cpp +++ b/storaged/main.cpp @@ -88,6 +88,8 @@ static int drop_privs() { void* storaged_main(void* s) { storaged_t* storaged = (storaged_t*)s; + storaged->init_battery_service(); + LOG_TO(SYSTEM, INFO) << "storaged: Start"; for (;;) { diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index 73df6d0d4..2f020742a 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -21,6 +21,9 @@ #include #include +#include +#include +#include #include #include @@ -157,6 +160,43 @@ void emmc_info_t::update(void) { } } +static sp get_battery_properties_service() { + sp sm = defaultServiceManager(); + if (sm == NULL) return NULL; + + sp binder = sm->getService(String16("batteryproperties")); + if (binder == NULL) return NULL; + + sp battery_properties = + interface_cast(binder); + + return battery_properties; +} + +static inline charger_stat_t is_charger_on(int64_t prop) { + return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ? + CHARGER_ON : CHARGER_OFF; +} + +void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) { + mUidm.set_charger_state(is_charger_on(props.batteryStatus)); +} + +void storaged_t::init_battery_service() { + sp battery_properties = get_battery_properties_service(); + if (battery_properties == NULL) { + LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service"; + return; + } + + struct BatteryProperty val; + battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val); + mUidm.init(is_charger_on(val.valueInt64)); + + // register listener after init uid_monitor + battery_properties->registerListener(this); +} + /* storaged_t */ storaged_t::storaged_t(void) { mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0); @@ -181,9 +221,8 @@ storaged_t::storaged_t(void) { mConfig.periodic_chores_interval_emmc_info_publish = property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH); - mUidm.set_periodic_chores_params( - property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO), - property_get_int32("ro.storaged.uid_io.threshold", DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD)); + mConfig.periodic_chores_interval_uid_io = + property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); mStarttime = time(NULL); } @@ -204,7 +243,7 @@ void storaged_t::event(void) { } if (mConfig.proc_uid_io_available && mTimer && - (mTimer % mUidm.get_periodic_chores_interval()) == 0) { + (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { mUidm.report(); } diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp index d81e0e54f..66354314e 100644 --- a/storaged/storaged_service.cpp +++ b/storaged/storaged_service.cpp @@ -99,20 +99,26 @@ status_t Storaged::dump(int fd, const Vector& args) { } } - const std::vector& events = storaged.get_uid_events(hours); - for (const auto& event : events) { - dprintf(fd, "%llu %s %llu %llu %llu %llu\n", - (unsigned long long)event.ts, - event.name.c_str(), - (unsigned long long)event.fg_read_bytes, - (unsigned long long)event.fg_write_bytes, - (unsigned long long)event.bg_read_bytes, - (unsigned long long)event.bg_write_bytes); + const std::map>& records = + storaged.get_uid_records(hours); + for (const auto& it : records) { + dprintf(fd, "%llu\n", (unsigned long long)it.first); + for (const auto& record : it.second) { + dprintf(fd, "%s %llu %llu %llu %llu %llu %llu %llu %llu\n", + record.name.c_str(), + (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_ON], + (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON], + (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_ON], + (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]); + } } return NO_ERROR; } - sp get_storaged_service() { sp sm = defaultServiceManager(); if (sm == NULL) return NULL; diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index 93c9df4cc..b46d09a75 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -49,20 +49,19 @@ static bool packagelist_parse_cb(pkg_info* info, void* userdata) return true; } -void uid_monitor::set_last_uids(std::unordered_map&& uids, - uint64_t ts) +std::unordered_map uid_monitor::get_uid_io_stats() { - last_uids = uids; - last_report_ts = ts; -} + std::unique_ptr lock(new lock_t(&um_lock)); + return get_uid_io_stats_locked(); +}; -std::unordered_map uid_monitor::get_uids() +std::unordered_map uid_monitor::get_uid_io_stats_locked() { - std::unordered_map uids; + std::unordered_map uid_io_stats; std::string buffer; if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) { PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed"; - return uids; + return uid_io_stats; } std::stringstream ss(buffer); @@ -70,144 +69,167 @@ std::unordered_map uid_monitor::get_uids() bool refresh_uid = false; while (ss >> u.uid) { - ss >> u.io[UID_FOREGROUND].rchar >> u.io[UID_FOREGROUND].wchar - >> u.io[UID_FOREGROUND].read_bytes >> u.io[UID_FOREGROUND].write_bytes - >> u.io[UID_BACKGROUND].rchar >> u.io[UID_BACKGROUND].wchar - >> u.io[UID_BACKGROUND].read_bytes >> u.io[UID_BACKGROUND].write_bytes; + ss >> u.io[FOREGROUND].rchar >> u.io[FOREGROUND].wchar + >> u.io[FOREGROUND].read_bytes >> u.io[FOREGROUND].write_bytes + >> u.io[BACKGROUND].rchar >> u.io[BACKGROUND].wchar + >> u.io[BACKGROUND].read_bytes >> u.io[BACKGROUND].write_bytes; if (!ss.good()) { ss.clear(std::ios_base::badbit); break; } - if (last_uids.find(u.uid) == last_uids.end()) { + if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) { refresh_uid = true; u.name = std::to_string(u.uid); } else { - u.name = last_uids[u.uid].name; + u.name = last_uid_io_stats[u.uid].name; } - uids[u.uid] = u; + uid_io_stats[u.uid] = u; } if (!ss.eof() || ss.bad()) { - uids.clear(); + uid_io_stats.clear(); LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed"; } if (refresh_uid) { - packagelist_parse(packagelist_parse_cb, &uids); + packagelist_parse(packagelist_parse_cb, &uid_io_stats); } - return uids; + return uid_io_stats; } -static const int MAX_UID_EVENTS_SIZE = 1000 * 48; // 1000 uids in 48 hours +static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours -void uid_monitor::add_events(const std::vector& new_events, - uint64_t curr_ts) +static inline int records_size( + const std::map>& records) { - std::unique_ptr lock(new lock_t(&events_lock)); - - // remove events more than 5 days old - struct uid_event first_event; - first_event.ts = curr_ts / SEC_TO_USEC - 5 * DAY_TO_SEC; - auto it = std::upper_bound(events.begin(), events.end(), first_event); - events.erase(events.begin(), it); - - // make some room for new events - int overflow = events.size() + new_events.size() - MAX_UID_EVENTS_SIZE; - if (overflow > 0) - events.erase(events.begin(), events.begin() + overflow); - - events.insert(events.end(), new_events.begin(), new_events.end()); + int count = 0; + for (auto const& it : records) { + count += it.second.size(); + } + return count; } -std::vector uid_monitor::dump_events(int hours) -{ - std::unique_ptr lock(new lock_t(&events_lock)); - std::vector dump_events; - struct timespec ts; +static struct uid_io_usage zero_io_usage; - if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { - PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; - return dump_events; +void uid_monitor::add_records_locked(uint64_t curr_ts) +{ + // remove records more than 5 days old + if (curr_ts > 5 * DAY_TO_SEC) { + auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC); + records.erase(records.begin(), it); } - struct uid_event first_event; - if (hours == 0) { - first_event.ts = 0; // dump all events - } else { - first_event.ts = ts.tv_sec - (uint64_t)hours * HOUR_TO_SEC; + std::vector new_records; + for (const auto& p : curr_io_stats) { + struct uid_record record = {}; + record.name = p.first; + record.ios = p.second; + if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) { + new_records.push_back(record); + } } - auto it = std::upper_bound(events.begin(), events.end(), first_event); - dump_events.assign(it, events.end()); + curr_io_stats.clear(); - return dump_events; + if (new_records.empty()) + return; + + // make some room for new records + int overflow = records_size(records) + + new_records.size() - MAX_UID_RECORDS_SIZE; + while (overflow > 0 && records.size() > 0) { + overflow -= records[0].size(); + records.erase(records.begin()); + } + + records[curr_ts].insert(records[curr_ts].end(), + new_records.begin(), new_records.end()); } -void uid_monitor::report() +std::map> uid_monitor::dump(int hours) { - struct timespec ts; + std::unique_ptr lock(new lock_t(&um_lock)); - // Use monotonic to exclude suspend time so that we measure IO bytes/sec - // when system is running. - if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { - PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; - return; + std::map> dump_records; + uint64_t first_ts = 0; + + if (hours != 0) { + first_ts = time(NULL) - (uint64_t)hours * HOUR_TO_SEC; } - uint64_t curr_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; - uint64_t ts_delta = curr_ts - last_report_ts; - uint64_t adjusted_threshold = threshold * ((double)ts_delta / interval / NS_PER_SEC); + dump_records.insert(records.lower_bound(first_ts), records.end()); + + return dump_records; +} - std::unordered_map uids = get_uids(); - if (uids.empty()) { +void uid_monitor::update_curr_io_stats_locked() +{ + std::unordered_map uid_io_stats = + get_uid_io_stats_locked(); + if (uid_io_stats.empty()) { return; } - std::vector new_events; - for (const auto& it : uids) { + for (const auto& it : uid_io_stats) { const struct uid_info& uid = it.second; - struct uid_event event; - - event.ts = ts.tv_sec; - event.name = uid.name; - event.fg_read_bytes = uid.io[UID_FOREGROUND].read_bytes - - last_uids[uid.uid].io[UID_FOREGROUND].read_bytes;; - event.fg_write_bytes = uid.io[UID_FOREGROUND].write_bytes - - last_uids[uid.uid].io[UID_FOREGROUND].write_bytes;; - event.bg_read_bytes = uid.io[UID_BACKGROUND].read_bytes - - last_uids[uid.uid].io[UID_BACKGROUND].read_bytes;; - event.bg_write_bytes = uid.io[UID_BACKGROUND].write_bytes - - last_uids[uid.uid].io[UID_BACKGROUND].write_bytes;; - - if (event.fg_read_bytes + event.fg_write_bytes + - event.bg_read_bytes + event.bg_write_bytes == 0) { - continue; + + if (curr_io_stats.find(uid.name) == curr_io_stats.end()) { + curr_io_stats[uid.name] = {}; } - new_events.push_back(event); + struct uid_io_usage& usage = curr_io_stats[uid.name]; + usage.bytes[READ][FOREGROUND][charger_stat] += + uid.io[FOREGROUND].read_bytes - + last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes; + usage.bytes[READ][BACKGROUND][charger_stat] += + uid.io[BACKGROUND].read_bytes - + last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes; + usage.bytes[WRITE][FOREGROUND][charger_stat] += + uid.io[FOREGROUND].write_bytes - + last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes; + usage.bytes[WRITE][BACKGROUND][charger_stat] += + uid.io[BACKGROUND].write_bytes - + last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;; } - add_events(new_events, curr_ts); - set_last_uids(std::move(uids), curr_ts); + last_uid_io_stats = uid_io_stats; } -uid_monitor::uid_monitor() +void uid_monitor::report() +{ + std::unique_ptr lock(new lock_t(&um_lock)); + + update_curr_io_stats_locked(); + add_records_locked(time(NULL)); +} + +void uid_monitor::set_charger_state(charger_stat_t stat) { - struct timespec ts; + std::unique_ptr lock(new lock_t(&um_lock)); - if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { - PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + if (charger_stat == stat) { return; } - last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; - sem_init(&events_lock, 0, 1); + update_curr_io_stats_locked(); + charger_stat = stat; +} + +void uid_monitor::init(charger_stat_t stat) +{ + charger_stat = stat; + last_uid_io_stats = get_uid_io_stats(); +} + +uid_monitor::uid_monitor() +{ + sem_init(&um_lock, 0, 1); } uid_monitor::~uid_monitor() { - sem_destroy(&events_lock); + sem_destroy(&um_lock); } diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp index 51ea64fdd..1ef89af68 100644 --- a/storaged/storaged_utils.cpp +++ b/storaged/storaged_utils.cpp @@ -247,7 +247,7 @@ bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) { static bool cmp_uid_info(struct uid_info l, struct uid_info r) { // Compare background I/O first. - for (int i = UID_STATS_SIZE - 1; i >= 0; i--) { + for (int i = UID_STATS - 1; i >= 0; i--) { uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes; uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes; uint64_t l_chars = l.io[i].rchar + l.io[i].wchar; -- cgit v1.2.3-54-g00ecf