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
This commit is contained in:
parent
72adf11daf
commit
5b962c6dbd
|
@ -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)
|
||||
|
|
|
@ -26,8 +26,12 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <batteryservice/IBatteryPropertiesListener.h>
|
||||
|
||||
#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<uint32_t, struct uid_info> get_uids(void) {
|
||||
return mUidm.get_uids();
|
||||
return mUidm.get_uid_io_stats();
|
||||
}
|
||||
std::vector<struct uid_event> get_uid_events(int hours) {
|
||||
return mUidm.dump_events(hours);
|
||||
std::map<uint64_t, std::vector<struct uid_record>> get_uid_records(int hours) {
|
||||
return mUidm.dump(hours);
|
||||
}
|
||||
|
||||
void init_battery_service();
|
||||
virtual void batteryPropertiesChanged(struct BatteryProperties props);
|
||||
};
|
||||
|
||||
// Eventlog tag
|
||||
|
|
|
@ -23,10 +23,22 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
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<uint32_t, struct uid_info> last_uids;
|
||||
std::vector<struct uid_event> events;
|
||||
sem_t events_lock;
|
||||
void set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& 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<uint32_t, struct uid_info> last_uid_io_stats;
|
||||
// current io usage for next report, app name -> uid_io_usage
|
||||
std::unordered_map<std::string, struct uid_io_usage> curr_io_stats;
|
||||
// io usage records, timestamp -> vector of events
|
||||
std::map<uint64_t, std::vector<struct uid_record>> 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<uint32_t, struct uid_info> 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<uint32_t, struct uid_info> get_uids();
|
||||
// called by storaged main thread
|
||||
void init(charger_stat_t stat);
|
||||
// called by storaged -u
|
||||
std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats();
|
||||
// called by dumpsys
|
||||
std::map<uint64_t, std::vector<struct uid_record>> 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<struct uid_event>& new_events, uint64_t curr_ts);
|
||||
std::vector<struct uid_event> dump_events(int hours);
|
||||
};
|
||||
|
||||
#endif /* _STORAGED_UID_MONITOR_H_ */
|
||||
|
|
|
@ -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 (;;) {
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <batteryservice/BatteryServiceConstants.h>
|
||||
#include <batteryservice/IBatteryPropertiesRegistrar.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <log/log.h>
|
||||
|
||||
|
@ -157,6 +160,43 @@ void emmc_info_t::update(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
|
||||
sp<IServiceManager> sm = defaultServiceManager();
|
||||
if (sm == NULL) return NULL;
|
||||
|
||||
sp<IBinder> binder = sm->getService(String16("batteryproperties"));
|
||||
if (binder == NULL) return NULL;
|
||||
|
||||
sp<IBatteryPropertiesRegistrar> battery_properties =
|
||||
interface_cast<IBatteryPropertiesRegistrar>(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<IBatteryPropertiesRegistrar> 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -99,20 +99,26 @@ status_t Storaged::dump(int fd, const Vector<String16>& args) {
|
|||
}
|
||||
}
|
||||
|
||||
const std::vector<struct uid_event>& 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<uint64_t, std::vector<struct uid_record>>& 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<IStoraged> get_storaged_service() {
|
||||
sp<IServiceManager> sm = defaultServiceManager();
|
||||
if (sm == NULL) return NULL;
|
||||
|
|
|
@ -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<uint32_t, struct uid_info>&& uids,
|
||||
uint64_t ts)
|
||||
std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
|
||||
{
|
||||
last_uids = uids;
|
||||
last_report_ts = ts;
|
||||
}
|
||||
std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
|
||||
return get_uid_io_stats_locked();
|
||||
};
|
||||
|
||||
std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uids()
|
||||
std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
|
||||
{
|
||||
std::unordered_map<uint32_t, struct uid_info> uids;
|
||||
std::unordered_map<uint32_t, struct uid_info> 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<uint32_t, struct uid_info> 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<struct uid_event>& new_events,
|
||||
uint64_t curr_ts)
|
||||
static inline int records_size(
|
||||
const std::map<uint64_t, std::vector<struct uid_record>>& records)
|
||||
{
|
||||
std::unique_ptr<lock_t> 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<struct uid_event> uid_monitor::dump_events(int hours)
|
||||
static struct uid_io_usage zero_io_usage;
|
||||
|
||||
void uid_monitor::add_records_locked(uint64_t curr_ts)
|
||||
{
|
||||
std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
|
||||
std::vector<struct uid_event> dump_events;
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
|
||||
PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
|
||||
return dump_events;
|
||||
// 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<struct uid_record> 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());
|
||||
}
|
||||
|
||||
std::map<uint64_t, std::vector<struct uid_record>> uid_monitor::dump(int hours)
|
||||
{
|
||||
std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
|
||||
|
||||
std::map<uint64_t, std::vector<struct uid_record>> dump_records;
|
||||
uint64_t first_ts = 0;
|
||||
|
||||
if (hours != 0) {
|
||||
first_ts = time(NULL) - (uint64_t)hours * HOUR_TO_SEC;
|
||||
}
|
||||
|
||||
dump_records.insert(records.lower_bound(first_ts), records.end());
|
||||
|
||||
return dump_records;
|
||||
}
|
||||
|
||||
void uid_monitor::update_curr_io_stats_locked()
|
||||
{
|
||||
std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
|
||||
get_uid_io_stats_locked();
|
||||
if (uid_io_stats.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& it : uid_io_stats) {
|
||||
const struct uid_info& uid = it.second;
|
||||
|
||||
if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
|
||||
curr_io_stats[uid.name] = {};
|
||||
}
|
||||
|
||||
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;;
|
||||
}
|
||||
|
||||
last_uid_io_stats = uid_io_stats;
|
||||
}
|
||||
|
||||
void uid_monitor::report()
|
||||
{
|
||||
struct timespec ts;
|
||||
std::unique_ptr<lock_t> 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";
|
||||
update_curr_io_stats_locked();
|
||||
add_records_locked(time(NULL));
|
||||
}
|
||||
|
||||
void uid_monitor::set_charger_state(charger_stat_t stat)
|
||||
{
|
||||
std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
|
||||
|
||||
if (charger_stat == stat) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
update_curr_io_stats_locked();
|
||||
charger_stat = stat;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, struct uid_info> uids = get_uids();
|
||||
if (uids.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<struct uid_event> new_events;
|
||||
for (const auto& it : uids) {
|
||||
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;
|
||||
}
|
||||
|
||||
new_events.push_back(event);
|
||||
}
|
||||
|
||||
add_events(new_events, curr_ts);
|
||||
set_last_uids(std::move(uids), curr_ts);
|
||||
void uid_monitor::init(charger_stat_t stat)
|
||||
{
|
||||
charger_stat = stat;
|
||||
last_uid_io_stats = get_uid_io_stats();
|
||||
}
|
||||
|
||||
uid_monitor::uid_monitor()
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
|
||||
PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
|
||||
return;
|
||||
}
|
||||
last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
|
||||
|
||||
sem_init(&events_lock, 0, 1);
|
||||
sem_init(&um_lock, 0, 1);
|
||||
}
|
||||
|
||||
uid_monitor::~uid_monitor()
|
||||
{
|
||||
sem_destroy(&events_lock);
|
||||
sem_destroy(&um_lock);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue