storaged: store io_history as protobuf file on userdata
Convert storaged internal io_history to protobuf format and serialize it to userdata partition. Also load this file during storaged startup to reconstruct io history. Bug: 63740245 Change-Id: I0697525df1c31fdec20f5ed4e3e9363e2dde244f
This commit is contained in:
parent
e4f1ec315d
commit
ebf031be98
6 changed files with 210 additions and 15 deletions
|
|
@ -23,8 +23,10 @@ cc_defaults {
|
|||
"libbinder",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
"libprotobuf-cpp-lite",
|
||||
"libsysutils",
|
||||
"libutils",
|
||||
"libz",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
|
|
@ -46,10 +48,16 @@ cc_library_static {
|
|||
"storaged_service.cpp",
|
||||
"storaged_utils.cpp",
|
||||
"storaged_uid_monitor.cpp",
|
||||
"storaged.proto",
|
||||
],
|
||||
|
||||
logtags: ["EventLogTags.logtags"],
|
||||
|
||||
proto: {
|
||||
type: "lite",
|
||||
export_proto_headers: true,
|
||||
},
|
||||
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,13 +92,15 @@ private:
|
|||
// 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, end timestamp -> {start timestamp, vector of records}
|
||||
std::map<uint64_t, struct uid_records> records;
|
||||
std::map<uint64_t, struct uid_records> io_history;
|
||||
// charger ON/OFF
|
||||
charger_stat_t charger_stat;
|
||||
// protects curr_io_stats, last_uid_io_stats, records and charger_stat
|
||||
sem_t um_lock;
|
||||
// start time for IO records
|
||||
uint64_t start_ts;
|
||||
// protobuf file for io_history
|
||||
static const std::string io_history_proto_file;
|
||||
|
||||
// reads from /proc/uid_io/stats
|
||||
std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked();
|
||||
|
|
@ -106,6 +108,10 @@ private:
|
|||
void add_records_locked(uint64_t curr_ts);
|
||||
// updates curr_io_stats and set last_uid_io_stats
|
||||
void update_curr_io_stats_locked();
|
||||
// restores io_history from protobuf file
|
||||
void load_io_history_from_proto();
|
||||
// converts io_history to protobuf and writes to a file
|
||||
void flush_io_history_to_proto();
|
||||
|
||||
public:
|
||||
uid_monitor();
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ void storaged_t::event(void) {
|
|||
|
||||
if (mConfig.proc_uid_io_available && mTimer &&
|
||||
(mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
|
||||
mUidm.report();
|
||||
mUidm.report();
|
||||
}
|
||||
|
||||
mTimer += mConfig.periodic_chores_interval_unit;
|
||||
|
|
|
|||
42
storaged/storaged.proto
Normal file
42
storaged/storaged.proto
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
syntax = "proto2";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
package storaged_proto;
|
||||
option java_package = "com.android.storaged.proto";
|
||||
option java_outer_classname = "Storaged";
|
||||
|
||||
message IOUsage {
|
||||
optional uint64 rd_fg_chg_on = 1;
|
||||
optional uint64 rd_fg_chg_off = 2;
|
||||
optional uint64 rd_bg_chg_on = 3;
|
||||
optional uint64 rd_bg_chg_off = 4;
|
||||
optional uint64 wr_fg_chg_on = 5;
|
||||
optional uint64 wr_fg_chg_off = 6;
|
||||
optional uint64 wr_bg_chg_on = 7;
|
||||
optional uint64 wr_bg_chg_off = 8;
|
||||
}
|
||||
|
||||
message TaskIOUsage {
|
||||
optional string task_name = 1;
|
||||
optional IOUsage ios = 2;
|
||||
}
|
||||
|
||||
message UidRecord {
|
||||
optional string uid_name = 1;
|
||||
optional IOUsage uid_io = 2;
|
||||
repeated TaskIOUsage task_io = 3;
|
||||
}
|
||||
|
||||
message UidIORecords {
|
||||
optional uint64 start_ts = 1;
|
||||
repeated UidRecord entries = 2;
|
||||
}
|
||||
|
||||
message UidIOItem {
|
||||
optional uint64 end_ts = 1;
|
||||
optional UidIORecords records = 2;
|
||||
}
|
||||
|
||||
message UidIOHistoryProto {
|
||||
optional uint32 crc = 1;
|
||||
repeated UidIOItem items = 2;
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
on post-fs-data
|
||||
mkdir /data/misc/storaged 0700 root root
|
||||
restorecon /data/misc/storaged
|
||||
|
||||
service storaged /system/bin/storaged
|
||||
class main
|
||||
priority 10
|
||||
file /d/mmc0/mmc0:0001/ext_csd r
|
||||
writepid /dev/cpuset/system-background/tasks
|
||||
user root
|
||||
group package_info
|
||||
group package_info
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@
|
|||
#define LOG_TAG "storaged"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
@ -34,12 +37,19 @@
|
|||
|
||||
#include "storaged.h"
|
||||
#include "storaged_uid_monitor.h"
|
||||
#include "system/core/storaged/storaged.pb.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace android::base;
|
||||
using namespace android::content::pm;
|
||||
using namespace google::protobuf::io;
|
||||
using namespace storaged_proto;
|
||||
|
||||
static bool refresh_uid_names;
|
||||
static const uint32_t crc_init = 0x5108A4ED; /* STORAGED */
|
||||
|
||||
const std::string uid_monitor::io_history_proto_file =
|
||||
"/data/misc/storaged/io_history.proto";
|
||||
|
||||
std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
|
||||
{
|
||||
|
|
@ -187,11 +197,11 @@ std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_lock
|
|||
|
||||
static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
|
||||
|
||||
static inline int records_size(
|
||||
const std::map<uint64_t, struct uid_records>& curr_records)
|
||||
static inline size_t history_size(
|
||||
const std::map<uint64_t, struct uid_records>& history)
|
||||
{
|
||||
int count = 0;
|
||||
for (auto const& it : curr_records) {
|
||||
size_t count = 0;
|
||||
for (auto const& it : history) {
|
||||
count += it.second.entries.size();
|
||||
}
|
||||
return count;
|
||||
|
|
@ -201,8 +211,8 @@ 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);
|
||||
auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC);
|
||||
io_history.erase(io_history.begin(), it);
|
||||
}
|
||||
|
||||
struct uid_records new_records;
|
||||
|
|
@ -227,15 +237,15 @@ void uid_monitor::add_records_locked(uint64_t curr_ts)
|
|||
return;
|
||||
|
||||
// make some room for new records
|
||||
int overflow = records_size(records) +
|
||||
ssize_t overflow = history_size(io_history) +
|
||||
new_records.entries.size() - MAX_UID_RECORDS_SIZE;
|
||||
while (overflow > 0 && records.size() > 0) {
|
||||
auto del_it = records.begin();
|
||||
while (overflow > 0 && io_history.size() > 0) {
|
||||
auto del_it = io_history.begin();
|
||||
overflow -= del_it->second.entries.size();
|
||||
records.erase(records.begin());
|
||||
io_history.erase(io_history.begin());
|
||||
}
|
||||
|
||||
records[curr_ts] = new_records;
|
||||
io_history[curr_ts] = new_records;
|
||||
}
|
||||
|
||||
std::map<uint64_t, struct uid_records> uid_monitor::dump(
|
||||
|
|
@ -254,7 +264,7 @@ std::map<uint64_t, struct uid_records> uid_monitor::dump(
|
|||
first_ts = time(NULL) - hours * HOUR_TO_SEC;
|
||||
}
|
||||
|
||||
for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
|
||||
for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) {
|
||||
const std::vector<struct uid_record>& recs = it->second.entries;
|
||||
struct uid_records filtered;
|
||||
|
||||
|
|
@ -351,6 +361,128 @@ void uid_monitor::report()
|
|||
|
||||
update_curr_io_stats_locked();
|
||||
add_records_locked(time(NULL));
|
||||
|
||||
flush_io_history_to_proto();
|
||||
}
|
||||
|
||||
static void set_io_usage_proto(IOUsage* usage_proto, const struct io_usage& usage)
|
||||
{
|
||||
usage_proto->set_rd_fg_chg_on(usage.bytes[READ][FOREGROUND][CHARGER_ON]);
|
||||
usage_proto->set_rd_fg_chg_off(usage.bytes[READ][FOREGROUND][CHARGER_OFF]);
|
||||
usage_proto->set_rd_bg_chg_on(usage.bytes[READ][BACKGROUND][CHARGER_ON]);
|
||||
usage_proto->set_rd_bg_chg_off(usage.bytes[READ][BACKGROUND][CHARGER_OFF]);
|
||||
usage_proto->set_wr_fg_chg_on(usage.bytes[WRITE][FOREGROUND][CHARGER_ON]);
|
||||
usage_proto->set_wr_fg_chg_off(usage.bytes[WRITE][FOREGROUND][CHARGER_OFF]);
|
||||
usage_proto->set_wr_bg_chg_on(usage.bytes[WRITE][BACKGROUND][CHARGER_ON]);
|
||||
usage_proto->set_wr_bg_chg_off(usage.bytes[WRITE][BACKGROUND][CHARGER_OFF]);
|
||||
}
|
||||
|
||||
static void get_io_usage_proto(struct io_usage* usage, const IOUsage& io_proto)
|
||||
{
|
||||
usage->bytes[READ][FOREGROUND][CHARGER_ON] = io_proto.rd_fg_chg_on();
|
||||
usage->bytes[READ][FOREGROUND][CHARGER_OFF] = io_proto.rd_fg_chg_off();
|
||||
usage->bytes[READ][BACKGROUND][CHARGER_ON] = io_proto.rd_bg_chg_on();
|
||||
usage->bytes[READ][BACKGROUND][CHARGER_OFF] = io_proto.rd_bg_chg_off();
|
||||
usage->bytes[WRITE][FOREGROUND][CHARGER_ON] = io_proto.wr_fg_chg_on();
|
||||
usage->bytes[WRITE][FOREGROUND][CHARGER_OFF] = io_proto.wr_fg_chg_off();
|
||||
usage->bytes[WRITE][BACKGROUND][CHARGER_ON] = io_proto.wr_bg_chg_on();
|
||||
usage->bytes[WRITE][BACKGROUND][CHARGER_OFF] = io_proto.wr_bg_chg_off();
|
||||
}
|
||||
|
||||
void uid_monitor::flush_io_history_to_proto()
|
||||
{
|
||||
UidIOHistoryProto out_proto;
|
||||
|
||||
for (const auto& item : io_history) {
|
||||
const uint64_t& end_ts = item.first;
|
||||
const struct uid_records& recs = item.second;
|
||||
|
||||
UidIOItem* item_proto = out_proto.add_items();
|
||||
item_proto->set_end_ts(end_ts);
|
||||
|
||||
UidIORecords* recs_proto = item_proto->mutable_records();
|
||||
recs_proto->set_start_ts(recs.start_ts);
|
||||
|
||||
for (const auto& entry : recs.entries) {
|
||||
UidRecord* rec_proto = recs_proto->add_entries();
|
||||
rec_proto->set_uid_name(entry.name);
|
||||
|
||||
IOUsage* uid_io_proto = rec_proto->mutable_uid_io();
|
||||
const struct io_usage& uio_ios = entry.ios.uid_ios;
|
||||
set_io_usage_proto(uid_io_proto, uio_ios);
|
||||
|
||||
for (const auto& task_io : entry.ios.task_ios) {
|
||||
const std::string& task_name = task_io.first;
|
||||
const struct io_usage& task_ios = task_io.second;
|
||||
|
||||
TaskIOUsage* task_io_proto = rec_proto->add_task_io();
|
||||
task_io_proto->set_task_name(task_name);
|
||||
set_io_usage_proto(task_io_proto->mutable_ios(), task_ios);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_proto.set_crc(crc_init);
|
||||
std::string out_proto_str = out_proto.SerializeAsString();
|
||||
out_proto.set_crc(crc32(crc_init,
|
||||
reinterpret_cast<const Bytef*>(out_proto_str.c_str()),
|
||||
out_proto_str.size()));
|
||||
|
||||
std::string tmp_file = io_history_proto_file + "_tmp";
|
||||
std::ofstream out(tmp_file,
|
||||
std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
|
||||
out << out_proto.SerializeAsString();
|
||||
out.close();
|
||||
|
||||
/* Atomically replace existing proto file to reduce chance of data loss. */
|
||||
rename(tmp_file.c_str(), io_history_proto_file.c_str());
|
||||
}
|
||||
|
||||
void uid_monitor::load_io_history_from_proto()
|
||||
{
|
||||
std::ifstream in(io_history_proto_file,
|
||||
std::ofstream::in | std::ofstream::binary);
|
||||
|
||||
if (!in.good()) {
|
||||
PLOG_TO(SYSTEM, INFO) << "Open " << io_history_proto_file << " failed";
|
||||
return;
|
||||
}
|
||||
|
||||
stringstream ss;
|
||||
ss << in.rdbuf();
|
||||
UidIOHistoryProto in_proto;
|
||||
in_proto.ParseFromString(ss.str());
|
||||
|
||||
uint32_t crc = in_proto.crc();
|
||||
in_proto.set_crc(crc_init);
|
||||
std::string io_proto_str = in_proto.SerializeAsString();
|
||||
uint32_t computed_crc = crc32(crc_init,
|
||||
reinterpret_cast<const Bytef*>(io_proto_str.c_str()),
|
||||
io_proto_str.size());
|
||||
|
||||
if (crc != computed_crc) {
|
||||
LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << io_history_proto_file;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& item_proto : in_proto.items()) {
|
||||
const UidIORecords& records_proto = item_proto.records();
|
||||
struct uid_records* recs = &io_history[item_proto.end_ts()];
|
||||
|
||||
recs->start_ts = records_proto.start_ts();
|
||||
for (const auto& rec_proto : records_proto.entries()) {
|
||||
struct uid_record record;
|
||||
record.name = rec_proto.uid_name();
|
||||
get_io_usage_proto(&record.ios.uid_ios, rec_proto.uid_io());
|
||||
|
||||
for (const auto& task_io_proto : rec_proto.task_io()) {
|
||||
get_io_usage_proto(
|
||||
&record.ios.task_ios[task_io_proto.task_name()],
|
||||
task_io_proto.ios());
|
||||
}
|
||||
recs->entries.push_back(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uid_monitor::set_charger_state(charger_stat_t stat)
|
||||
|
|
@ -368,6 +500,9 @@ void uid_monitor::set_charger_state(charger_stat_t stat)
|
|||
void uid_monitor::init(charger_stat_t stat)
|
||||
{
|
||||
charger_stat = stat;
|
||||
|
||||
load_io_history_from_proto();
|
||||
|
||||
start_ts = time(NULL);
|
||||
last_uid_io_stats = get_uid_io_stats();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue