summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJin Qian2017-01-30 16:48:38 -0600
committerJin Qian2017-02-07 15:41:15 -0600
commit5b962c6dbd305946ece05ffbd81d29c2ea211673 (patch)
tree83eaea2fa01a5b5f881d531052548103e258469a /storaged
parent72adf11daf55f98179fafab98ccb6bcfd309de19 (diff)
downloadplatform-system-core-5b962c6dbd305946ece05ffbd81d29c2ea211673.tar.gz
platform-system-core-5b962c6dbd305946ece05ffbd81d29c2ea211673.tar.xz
platform-system-core-5b962c6dbd305946ece05ffbd81d29c2ea211673.zip
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
Diffstat (limited to 'storaged')
-rw-r--r--storaged/Android.mk23
-rw-r--r--storaged/include/storaged.h15
-rw-r--r--storaged/include/storaged_uid_monitor.h76
-rw-r--r--storaged/main.cpp2
-rw-r--r--storaged/storaged.cpp47
-rw-r--r--storaged/storaged_service.cpp26
-rw-r--r--storaged/storaged_uid_monitor.cpp204
-rw-r--r--storaged/storaged_utils.cpp2
8 files changed, 252 insertions, 143 deletions
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 @@
2 2
3LOCAL_PATH := $(call my-dir) 3LOCAL_PATH := $(call my-dir)
4 4
5LIBSTORAGED_SHARED_LIBRARIES := libbinder libbase libutils libcutils liblog libsysutils libcap libpackagelistparser 5LIBSTORAGED_SHARED_LIBRARIES := \
6 libbinder \
7 libbase \
8 libutils \
9 libcutils \
10 liblog \
11 libsysutils \
12 libcap \
13 libpackagelistparser \
14 libbatteryservice \
6 15
7include $(CLEAR_VARS) 16include $(CLEAR_VARS)
8 17
9LOCAL_SRC_FILES := storaged.cpp \ 18LOCAL_SRC_FILES := \
10 storaged_service.cpp \ 19 storaged.cpp \
11 storaged_utils.cpp \ 20 storaged_service.cpp \
12 storaged_uid_monitor.cpp \ 21 storaged_utils.cpp \
13 EventLogTags.logtags 22 storaged_uid_monitor.cpp \
23 EventLogTags.logtags
14 24
15LOCAL_MODULE := libstoraged 25LOCAL_MODULE := libstoraged
16LOCAL_CFLAGS := -Werror 26LOCAL_CFLAGS := -Werror
17LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include 27LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include
18LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include 28LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
19LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES) 29LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
20
21include $(BUILD_STATIC_LIBRARY) 30include $(BUILD_STATIC_LIBRARY)
22 31
23include $(CLEAR_VARS) 32include $(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 @@
26#include <unordered_map> 26#include <unordered_map>
27#include <vector> 27#include <vector>
28 28
29#include <batteryservice/IBatteryPropertiesListener.h>
30
29#include "storaged_uid_monitor.h" 31#include "storaged_uid_monitor.h"
30 32
33using namespace android;
34
31#define FRIEND_TEST(test_case_name, test_name) \ 35#define FRIEND_TEST(test_case_name, test_name) \
32friend class test_case_name##_##test_name##_Test 36friend class test_case_name##_##test_name##_Test
33 37
@@ -268,7 +272,7 @@ struct storaged_config {
268 int event_time_check_usec; // check how much cputime spent in event loop 272 int event_time_check_usec; // check how much cputime spent in event loop
269}; 273};
270 274
271class storaged_t { 275class storaged_t : public BnBatteryPropertiesListener {
272private: 276private:
273 time_t mTimer; 277 time_t mTimer;
274 storaged_config mConfig; 278 storaged_config mConfig;
@@ -294,11 +298,14 @@ public:
294 } 298 }
295 299
296 std::unordered_map<uint32_t, struct uid_info> get_uids(void) { 300 std::unordered_map<uint32_t, struct uid_info> get_uids(void) {
297 return mUidm.get_uids(); 301 return mUidm.get_uid_io_stats();
298 } 302 }
299 std::vector<struct uid_event> get_uid_events(int hours) { 303 std::map<uint64_t, std::vector<struct uid_record>> get_uid_records(int hours) {
300 return mUidm.dump_events(hours); 304 return mUidm.dump(hours);
301 } 305 }
306
307 void init_battery_service();
308 virtual void batteryPropertiesChanged(struct BatteryProperties props);
302}; 309};
303 310
304// Eventlog tag 311// 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 @@
23#include <unordered_map> 23#include <unordered_map>
24#include <vector> 24#include <vector>
25 25
26enum { 26enum uid_stat_t {
27 UID_FOREGROUND = 0, 27 FOREGROUND = 0,
28 UID_BACKGROUND = 1, 28 BACKGROUND = 1,
29 UID_STATS_SIZE = 2 29 UID_STATS = 2
30};
31
32enum charger_stat_t {
33 CHARGER_OFF = 0,
34 CHARGER_ON = 1,
35 CHARGER_STATS = 2
36};
37
38enum io_type_t {
39 READ = 0,
40 WRITE = 1,
41 IO_TYPES = 2
30}; 42};
31 43
32struct uid_io_stats { 44struct uid_io_stats {
@@ -39,39 +51,51 @@ struct uid_io_stats {
39struct uid_info { 51struct uid_info {
40 uint32_t uid; // user id 52 uint32_t uid; // user id
41 std::string name; // package name 53 std::string name; // package name
42 struct uid_io_stats io[UID_STATS_SIZE]; // [0]:foreground [1]:background 54 struct uid_io_stats io[UID_STATS]; // [0]:foreground [1]:background
43}; 55};
44 56
45struct uid_event { 57struct uid_io_usage {
58 uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS];
59};
60
61struct uid_record {
46 std::string name; 62 std::string name;
47 uint64_t fg_read_bytes; 63 struct uid_io_usage ios;
48 uint64_t fg_write_bytes;
49 uint64_t bg_read_bytes;
50 uint64_t bg_write_bytes;
51 uint64_t ts;
52 bool operator< (const struct uid_event& e) const {
53 return ts < e.ts;
54 }
55}; 64};
56 65
57class uid_monitor { 66class uid_monitor {
58private: 67private:
59 std::unordered_map<uint32_t, struct uid_info> last_uids; 68 // last dump from /proc/uid_io/stats, uid -> uid_info
60 std::vector<struct uid_event> events; 69 std::unordered_map<uint32_t, struct uid_info> last_uid_io_stats;
61 sem_t events_lock; 70 // current io usage for next report, app name -> uid_io_usage
62 void set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& uids, uint64_t ts); 71 std::unordered_map<std::string, struct uid_io_usage> curr_io_stats;
63 int interval; // monitor interval in seconds 72 // io usage records, timestamp -> vector of events
64 int threshold; // monitor threshold in bytes 73 std::map<uint64_t, std::vector<struct uid_record>> records;
65 uint64_t last_report_ts; // timestamp of last report in nsec 74 // charger ON/OFF
75 charger_stat_t charger_stat;
76 // protects curr_io_stats, last_uid_io_stats, records and charger_stat
77 sem_t um_lock;
78
79 // reads from /proc/uid_io/stats
80 std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked();
81 // flushes curr_io_stats to records
82 void add_records_locked(uint64_t curr_ts);
83 // updates curr_io_stats and set last_uid_io_stats
84 void update_curr_io_stats_locked();
85
66public: 86public:
67 uid_monitor(); 87 uid_monitor();
68 ~uid_monitor(); 88 ~uid_monitor();
69 void set_periodic_chores_params(int intvl, int thold) { interval = intvl; threshold = thold; } 89 // called by storaged main thread
70 int get_periodic_chores_interval() { return interval; } 90 void init(charger_stat_t stat);
71 std::unordered_map<uint32_t, struct uid_info> get_uids(); 91 // called by storaged -u
92 std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats();
93 // called by dumpsys
94 std::map<uint64_t, std::vector<struct uid_record>> dump(int hours);
95 // called by battery properties listener
96 void set_charger_state(charger_stat_t stat);
97 // called by storaged periodic_chore
72 void report(); 98 void report();
73 void add_events(const std::vector<struct uid_event>& new_events, uint64_t curr_ts);
74 std::vector<struct uid_event> dump_events(int hours);
75}; 99};
76 100
77#endif /* _STORAGED_UID_MONITOR_H_ */ 101#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() {
88void* storaged_main(void* s) { 88void* storaged_main(void* s) {
89 storaged_t* storaged = (storaged_t*)s; 89 storaged_t* storaged = (storaged_t*)s;
90 90
91 storaged->init_battery_service();
92
91 LOG_TO(SYSTEM, INFO) << "storaged: Start"; 93 LOG_TO(SYSTEM, INFO) << "storaged: Start";
92 94
93 for (;;) { 95 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 @@
21#include <unistd.h> 21#include <unistd.h>
22 22
23#include <android-base/logging.h> 23#include <android-base/logging.h>
24#include <batteryservice/BatteryServiceConstants.h>
25#include <batteryservice/IBatteryPropertiesRegistrar.h>
26#include <binder/IServiceManager.h>
24#include <cutils/properties.h> 27#include <cutils/properties.h>
25#include <log/log.h> 28#include <log/log.h>
26 29
@@ -157,6 +160,43 @@ void emmc_info_t::update(void) {
157 } 160 }
158} 161}
159 162
163static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
164 sp<IServiceManager> sm = defaultServiceManager();
165 if (sm == NULL) return NULL;
166
167 sp<IBinder> binder = sm->getService(String16("batteryproperties"));
168 if (binder == NULL) return NULL;
169
170 sp<IBatteryPropertiesRegistrar> battery_properties =
171 interface_cast<IBatteryPropertiesRegistrar>(binder);
172
173 return battery_properties;
174}
175
176static inline charger_stat_t is_charger_on(int64_t prop) {
177 return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
178 CHARGER_ON : CHARGER_OFF;
179}
180
181void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
182 mUidm.set_charger_state(is_charger_on(props.batteryStatus));
183}
184
185void storaged_t::init_battery_service() {
186 sp<IBatteryPropertiesRegistrar> battery_properties = get_battery_properties_service();
187 if (battery_properties == NULL) {
188 LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
189 return;
190 }
191
192 struct BatteryProperty val;
193 battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
194 mUidm.init(is_charger_on(val.valueInt64));
195
196 // register listener after init uid_monitor
197 battery_properties->registerListener(this);
198}
199
160/* storaged_t */ 200/* storaged_t */
161storaged_t::storaged_t(void) { 201storaged_t::storaged_t(void) {
162 mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0); 202 mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0);
@@ -181,9 +221,8 @@ storaged_t::storaged_t(void) {
181 mConfig.periodic_chores_interval_emmc_info_publish = 221 mConfig.periodic_chores_interval_emmc_info_publish =
182 property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH); 222 property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH);
183 223
184 mUidm.set_periodic_chores_params( 224 mConfig.periodic_chores_interval_uid_io =
185 property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO), 225 property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
186 property_get_int32("ro.storaged.uid_io.threshold", DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD));
187 226
188 mStarttime = time(NULL); 227 mStarttime = time(NULL);
189} 228}
@@ -204,7 +243,7 @@ void storaged_t::event(void) {
204 } 243 }
205 244
206 if (mConfig.proc_uid_io_available && mTimer && 245 if (mConfig.proc_uid_io_available && mTimer &&
207 (mTimer % mUidm.get_periodic_chores_interval()) == 0) { 246 (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
208 mUidm.report(); 247 mUidm.report();
209 } 248 }
210 249
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<String16>& args) {
99 } 99 }
100 } 100 }
101 101
102 const std::vector<struct uid_event>& events = storaged.get_uid_events(hours); 102 const std::map<uint64_t, std::vector<struct uid_record>>& records =
103 for (const auto& event : events) { 103 storaged.get_uid_records(hours);
104 dprintf(fd, "%llu %s %llu %llu %llu %llu\n", 104 for (const auto& it : records) {
105 (unsigned long long)event.ts, 105 dprintf(fd, "%llu\n", (unsigned long long)it.first);
106 event.name.c_str(), 106 for (const auto& record : it.second) {
107 (unsigned long long)event.fg_read_bytes, 107 dprintf(fd, "%s %llu %llu %llu %llu %llu %llu %llu %llu\n",
108 (unsigned long long)event.fg_write_bytes, 108 record.name.c_str(),
109 (unsigned long long)event.bg_read_bytes, 109 (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_OFF],
110 (unsigned long long)event.bg_write_bytes); 110 (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF],
111 (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_OFF],
112 (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF],
113 (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_ON],
114 (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON],
115 (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_ON],
116 (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]);
117 }
111 } 118 }
112 return NO_ERROR; 119 return NO_ERROR;
113} 120}
114 121
115
116sp<IStoraged> get_storaged_service() { 122sp<IStoraged> get_storaged_service() {
117 sp<IServiceManager> sm = defaultServiceManager(); 123 sp<IServiceManager> sm = defaultServiceManager();
118 if (sm == NULL) return NULL; 124 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)
49 return true; 49 return true;
50} 50}
51 51
52void uid_monitor::set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& uids, 52std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
53 uint64_t ts)
54{ 53{
55 last_uids = uids; 54 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
56 last_report_ts = ts; 55 return get_uid_io_stats_locked();
57} 56};
58 57
59std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uids() 58std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
60{ 59{
61 std::unordered_map<uint32_t, struct uid_info> uids; 60 std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
62 std::string buffer; 61 std::string buffer;
63 if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) { 62 if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
64 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed"; 63 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
65 return uids; 64 return uid_io_stats;
66 } 65 }
67 66
68 std::stringstream ss(buffer); 67 std::stringstream ss(buffer);
@@ -70,144 +69,167 @@ std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uids()
70 bool refresh_uid = false; 69 bool refresh_uid = false;
71 70
72 while (ss >> u.uid) { 71 while (ss >> u.uid) {
73 ss >> u.io[UID_FOREGROUND].rchar >> u.io[UID_FOREGROUND].wchar 72 ss >> u.io[FOREGROUND].rchar >> u.io[FOREGROUND].wchar
74 >> u.io[UID_FOREGROUND].read_bytes >> u.io[UID_FOREGROUND].write_bytes 73 >> u.io[FOREGROUND].read_bytes >> u.io[FOREGROUND].write_bytes
75 >> u.io[UID_BACKGROUND].rchar >> u.io[UID_BACKGROUND].wchar 74 >> u.io[BACKGROUND].rchar >> u.io[BACKGROUND].wchar
76 >> u.io[UID_BACKGROUND].read_bytes >> u.io[UID_BACKGROUND].write_bytes; 75 >> u.io[BACKGROUND].read_bytes >> u.io[BACKGROUND].write_bytes;
77 76
78 if (!ss.good()) { 77 if (!ss.good()) {
79 ss.clear(std::ios_base::badbit); 78 ss.clear(std::ios_base::badbit);
80 break; 79 break;
81 } 80 }
82 81
83 if (last_uids.find(u.uid) == last_uids.end()) { 82 if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
84 refresh_uid = true; 83 refresh_uid = true;
85 u.name = std::to_string(u.uid); 84 u.name = std::to_string(u.uid);
86 } else { 85 } else {
87 u.name = last_uids[u.uid].name; 86 u.name = last_uid_io_stats[u.uid].name;
88 } 87 }
89 uids[u.uid] = u; 88 uid_io_stats[u.uid] = u;
90 } 89 }
91 90
92 if (!ss.eof() || ss.bad()) { 91 if (!ss.eof() || ss.bad()) {
93 uids.clear(); 92 uid_io_stats.clear();
94 LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed"; 93 LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed";
95 } 94 }
96 95
97 if (refresh_uid) { 96 if (refresh_uid) {
98 packagelist_parse(packagelist_parse_cb, &uids); 97 packagelist_parse(packagelist_parse_cb, &uid_io_stats);
99 } 98 }
100 99
101 return uids; 100 return uid_io_stats;
102} 101}
103 102
104static const int MAX_UID_EVENTS_SIZE = 1000 * 48; // 1000 uids in 48 hours 103static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
105 104
106void uid_monitor::add_events(const std::vector<struct uid_event>& new_events, 105static inline int records_size(
107 uint64_t curr_ts) 106 const std::map<uint64_t, std::vector<struct uid_record>>& records)
108{ 107{
109 std::unique_ptr<lock_t> lock(new lock_t(&events_lock)); 108 int count = 0;
110 109 for (auto const& it : records) {
111 // remove events more than 5 days old 110 count += it.second.size();
112 struct uid_event first_event; 111 }
113 first_event.ts = curr_ts / SEC_TO_USEC - 5 * DAY_TO_SEC; 112 return count;
114 auto it = std::upper_bound(events.begin(), events.end(), first_event);
115 events.erase(events.begin(), it);
116
117 // make some room for new events
118 int overflow = events.size() + new_events.size() - MAX_UID_EVENTS_SIZE;
119 if (overflow > 0)
120 events.erase(events.begin(), events.begin() + overflow);
121
122 events.insert(events.end(), new_events.begin(), new_events.end());
123} 113}
124 114
125std::vector<struct uid_event> uid_monitor::dump_events(int hours) 115static struct uid_io_usage zero_io_usage;
126{
127 std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
128 std::vector<struct uid_event> dump_events;
129 struct timespec ts;
130 116
131 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { 117void uid_monitor::add_records_locked(uint64_t curr_ts)
132 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 118{
133 return dump_events; 119 // remove records more than 5 days old
120 if (curr_ts > 5 * DAY_TO_SEC) {
121 auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
122 records.erase(records.begin(), it);
134 } 123 }
135 124
136 struct uid_event first_event; 125 std::vector<struct uid_record> new_records;
137 if (hours == 0) { 126 for (const auto& p : curr_io_stats) {
138 first_event.ts = 0; // dump all events 127 struct uid_record record = {};
139 } else { 128 record.name = p.first;
140 first_event.ts = ts.tv_sec - (uint64_t)hours * HOUR_TO_SEC; 129 record.ios = p.second;
130 if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) {
131 new_records.push_back(record);
132 }
141 } 133 }
142 auto it = std::upper_bound(events.begin(), events.end(), first_event);
143 134
144 dump_events.assign(it, events.end()); 135 curr_io_stats.clear();
145 136
146 return dump_events; 137 if (new_records.empty())
138 return;
139
140 // make some room for new records
141 int overflow = records_size(records) +
142 new_records.size() - MAX_UID_RECORDS_SIZE;
143 while (overflow > 0 && records.size() > 0) {
144 overflow -= records[0].size();
145 records.erase(records.begin());
146 }
147
148 records[curr_ts].insert(records[curr_ts].end(),
149 new_records.begin(), new_records.end());
147} 150}
148 151
149void uid_monitor::report() 152std::map<uint64_t, std::vector<struct uid_record>> uid_monitor::dump(int hours)
150{ 153{
151 struct timespec ts; 154 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
152 155
153 // Use monotonic to exclude suspend time so that we measure IO bytes/sec 156 std::map<uint64_t, std::vector<struct uid_record>> dump_records;
154 // when system is running. 157 uint64_t first_ts = 0;
155 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { 158
156 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 159 if (hours != 0) {
157 return; 160 first_ts = time(NULL) - (uint64_t)hours * HOUR_TO_SEC;
158 } 161 }
159 162
160 uint64_t curr_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; 163 dump_records.insert(records.lower_bound(first_ts), records.end());
161 uint64_t ts_delta = curr_ts - last_report_ts; 164
162 uint64_t adjusted_threshold = threshold * ((double)ts_delta / interval / NS_PER_SEC); 165 return dump_records;
166}
163 167
164 std::unordered_map<uint32_t, struct uid_info> uids = get_uids(); 168void uid_monitor::update_curr_io_stats_locked()
165 if (uids.empty()) { 169{
170 std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
171 get_uid_io_stats_locked();
172 if (uid_io_stats.empty()) {
166 return; 173 return;
167 } 174 }
168 175
169 std::vector<struct uid_event> new_events; 176 for (const auto& it : uid_io_stats) {
170 for (const auto& it : uids) {
171 const struct uid_info& uid = it.second; 177 const struct uid_info& uid = it.second;
172 struct uid_event event; 178
173 179 if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
174 event.ts = ts.tv_sec; 180 curr_io_stats[uid.name] = {};
175 event.name = uid.name;
176 event.fg_read_bytes = uid.io[UID_FOREGROUND].read_bytes -
177 last_uids[uid.uid].io[UID_FOREGROUND].read_bytes;;
178 event.fg_write_bytes = uid.io[UID_FOREGROUND].write_bytes -
179 last_uids[uid.uid].io[UID_FOREGROUND].write_bytes;;
180 event.bg_read_bytes = uid.io[UID_BACKGROUND].read_bytes -
181 last_uids[uid.uid].io[UID_BACKGROUND].read_bytes;;
182 event.bg_write_bytes = uid.io[UID_BACKGROUND].write_bytes -
183 last_uids[uid.uid].io[UID_BACKGROUND].write_bytes;;
184
185 if (event.fg_read_bytes + event.fg_write_bytes +
186 event.bg_read_bytes + event.bg_write_bytes == 0) {
187 continue;
188 } 181 }
189 182
190 new_events.push_back(event); 183 struct uid_io_usage& usage = curr_io_stats[uid.name];
184 usage.bytes[READ][FOREGROUND][charger_stat] +=
185 uid.io[FOREGROUND].read_bytes -
186 last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
187 usage.bytes[READ][BACKGROUND][charger_stat] +=
188 uid.io[BACKGROUND].read_bytes -
189 last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
190 usage.bytes[WRITE][FOREGROUND][charger_stat] +=
191 uid.io[FOREGROUND].write_bytes -
192 last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
193 usage.bytes[WRITE][BACKGROUND][charger_stat] +=
194 uid.io[BACKGROUND].write_bytes -
195 last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;;
191 } 196 }
192 197
193 add_events(new_events, curr_ts); 198 last_uid_io_stats = uid_io_stats;
194 set_last_uids(std::move(uids), curr_ts);
195} 199}
196 200
197uid_monitor::uid_monitor() 201void uid_monitor::report()
202{
203 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
204
205 update_curr_io_stats_locked();
206 add_records_locked(time(NULL));
207}
208
209void uid_monitor::set_charger_state(charger_stat_t stat)
198{ 210{
199 struct timespec ts; 211 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
200 212
201 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { 213 if (charger_stat == stat) {
202 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
203 return; 214 return;
204 } 215 }
205 last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
206 216
207 sem_init(&events_lock, 0, 1); 217 update_curr_io_stats_locked();
218 charger_stat = stat;
219}
220
221void uid_monitor::init(charger_stat_t stat)
222{
223 charger_stat = stat;
224 last_uid_io_stats = get_uid_io_stats();
225}
226
227uid_monitor::uid_monitor()
228{
229 sem_init(&um_lock, 0, 1);
208} 230}
209 231
210uid_monitor::~uid_monitor() 232uid_monitor::~uid_monitor()
211{ 233{
212 sem_destroy(&events_lock); 234 sem_destroy(&um_lock);
213} 235}
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) {
247 247
248static bool cmp_uid_info(struct uid_info l, struct uid_info r) { 248static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
249 // Compare background I/O first. 249 // Compare background I/O first.
250 for (int i = UID_STATS_SIZE - 1; i >= 0; i--) { 250 for (int i = UID_STATS - 1; i >= 0; i--) {
251 uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes; 251 uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
252 uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes; 252 uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes;
253 uint64_t l_chars = l.io[i].rchar + l.io[i].wchar; 253 uint64_t l_chars = l.io[i].rchar + l.io[i].wchar;