storaged: add --hours flag for dumpsys
1. Add a flag to report IO usage for last N hours. 2. Change interval back to 1 hour so that we have finer usage data. 3. Don't clear events after dumpsys call. Use a max buffer limit. 4. Clear old events if they're more than 5 days old or when no room for new events. 5. Skip uids with no IO usage to save space. 6. Replace interval with a timestamp in event entry. Test: adb shell dumpsys storaged --hours 2 Bug: 34198239 Bug: 33086174 Change-Id: I66e8fb6ec155584115fab817c3ed2c78e637ac40
This commit is contained in:
parent
2bd3e9cefd
commit
9cdfdd3ff9
5 changed files with 70 additions and 26 deletions
|
|
@ -45,6 +45,8 @@ friend class test_case_name##_##test_name##_Test
|
|||
#define MSEC_TO_USEC ( 1000 )
|
||||
#define USEC_TO_NSEC ( 1000 )
|
||||
#define SEC_TO_USEC ( 1000000 )
|
||||
#define HOUR_TO_SEC ( 3600 )
|
||||
#define DAY_TO_SEC ( 3600 * 24 )
|
||||
|
||||
// number of attributes diskstats has
|
||||
#define DISK_STATS_SIZE ( 11 )
|
||||
|
|
@ -250,7 +252,7 @@ public:
|
|||
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
|
||||
#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
|
||||
#define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 )
|
||||
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 86400 )
|
||||
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
|
||||
|
||||
// UID IO threshold in bytes
|
||||
#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
|
||||
|
|
@ -294,8 +296,8 @@ public:
|
|||
std::unordered_map<uint32_t, struct uid_info> get_uids(void) {
|
||||
return mUidm.get_uids();
|
||||
}
|
||||
std::vector<struct uid_event> get_uid_events(void) {
|
||||
return mUidm.dump_events();
|
||||
std::vector<struct uid_event> get_uid_events(int hours) {
|
||||
return mUidm.dump_events(hours);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,10 @@ struct uid_event {
|
|||
uint64_t fg_write_bytes;
|
||||
uint64_t bg_read_bytes;
|
||||
uint64_t bg_write_bytes;
|
||||
uint64_t interval;
|
||||
uint64_t ts;
|
||||
bool operator< (const struct uid_event& e) const {
|
||||
return ts < e.ts;
|
||||
}
|
||||
};
|
||||
|
||||
class uid_monitor {
|
||||
|
|
@ -67,8 +70,8 @@ public:
|
|||
int get_periodic_chores_interval() { return interval; }
|
||||
std::unordered_map<uint32_t, struct uid_info> get_uids();
|
||||
void report();
|
||||
void add_event(const struct uid_event& event);
|
||||
std::vector<struct uid_event> dump_events();
|
||||
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_ */
|
||||
|
|
|
|||
|
|
@ -104,9 +104,6 @@ static void help_message(void) {
|
|||
fflush(stdout);
|
||||
}
|
||||
|
||||
#define HOUR_TO_SEC ( 3600 )
|
||||
#define DAY_TO_SEC ( 3600 * 24 )
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int flag_main_service = 0;
|
||||
int flag_dump_uid = 0;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ std::vector<struct uid_info> Storaged::dump_uids(const char* /* option */) {
|
|||
return uids_v;
|
||||
}
|
||||
|
||||
status_t Storaged::dump(int fd, const Vector<String16>& /* args */) {
|
||||
status_t Storaged::dump(int fd, const Vector<String16>& args) {
|
||||
IPCThreadState* self = IPCThreadState::self();
|
||||
const int pid = self->getCallingPid();
|
||||
const int uid = self->getCallingUid();
|
||||
|
|
@ -88,14 +88,26 @@ status_t Storaged::dump(int fd, const Vector<String16>& /* args */) {
|
|||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
const std::vector<struct uid_event>& events = storaged.get_uid_events();
|
||||
int hours = 0;
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
const auto& arg = args[i];
|
||||
if (arg == String16("--hours")) {
|
||||
if (++i >= args.size())
|
||||
break;
|
||||
hours = stoi(String16::std_string(args[i]));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<struct uid_event>& events = storaged.get_uid_events(hours);
|
||||
for (const auto& event : events) {
|
||||
dprintf(fd, "%s %llu %llu %llu %llu %llu\n", event.name.c_str(),
|
||||
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,
|
||||
(unsigned long long)event.interval);
|
||||
(unsigned long long)event.bg_write_bytes);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,25 +101,48 @@ std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uids()
|
|||
return uids;
|
||||
}
|
||||
|
||||
static const int MAX_UID_EVENTS = 1000;
|
||||
static const int MAX_UID_EVENTS_SIZE = 1000 * 48; // 1000 uids in 48 hours
|
||||
|
||||
void uid_monitor::add_event(const struct uid_event& event)
|
||||
void uid_monitor::add_events(const std::vector<struct uid_event>& new_events,
|
||||
uint64_t curr_ts)
|
||||
{
|
||||
std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
|
||||
|
||||
if (events.size() > MAX_UID_EVENTS) {
|
||||
LOG_TO(SYSTEM, ERROR) << "event buffer full";
|
||||
return;
|
||||
}
|
||||
events.push_back(event);
|
||||
// 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());
|
||||
}
|
||||
|
||||
std::vector<struct uid_event> uid_monitor::dump_events()
|
||||
std::vector<struct uid_event> uid_monitor::dump_events(int hours)
|
||||
{
|
||||
std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
|
||||
std::vector<struct uid_event> dump_events = events;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
auto it = std::upper_bound(events.begin(), events.end(), first_event);
|
||||
|
||||
dump_events.assign(it, events.end());
|
||||
|
||||
events.clear();
|
||||
return dump_events;
|
||||
}
|
||||
|
||||
|
|
@ -143,10 +166,12 @@ void uid_monitor::report()
|
|||
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;;
|
||||
|
|
@ -156,11 +181,16 @@ void uid_monitor::report()
|
|||
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;;
|
||||
event.interval = uint64_t(ts_delta / NS_PER_SEC);
|
||||
|
||||
add_event(event);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue