From 3790f5bfafc52ca881b9350b922ffe94e6a537bb Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Mon, 23 Jan 2017 14:38:47 -0800 Subject: storaged: replace cmd arguments with properties Add properties to control event intervals. Add a property to check time spent in event loop. Bug: 34612341 Bug: 34198239 Change-Id: I01f64c84e17153377ece7ae530be106e3f55287e --- storaged/README.properties | 6 +++ storaged/include/storaged.h | 25 +++++------ storaged/include/storaged_uid_monitor.h | 5 ++- storaged/main.cpp | 77 +-------------------------------- storaged/storaged.cpp | 47 ++++++++++++++++++-- storaged/storaged_uid_monitor.cpp | 4 +- storaged/storaged_utils.cpp | 5 --- 7 files changed, 67 insertions(+), 102 deletions(-) create mode 100644 storaged/README.properties diff --git a/storaged/README.properties b/storaged/README.properties new file mode 100644 index 000000000..70e6026f0 --- /dev/null +++ b/storaged/README.properties @@ -0,0 +1,6 @@ +ro.storaged.event.interval # interval storaged scans for IO stats, in seconds +ro.storaged.event.perf_check # check for time spent in event loop, in microseconds +ro.storaged.disk_stats_pub # interval storaged publish disk stats, in seconds +ro.storaged.emmc_info_pub # interval storaged publish emmc info, in seconds +ro.storaged.uid_io.interval # interval storaged checks Per UID IO usage, in seconds +ro.storaged.uid_io.threshold # Per UID IO usage limit, in bytes diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index 7fa9958bd..d3e6b7140 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -40,6 +40,12 @@ friend class test_case_name##_##test_name##_Test #define debuginfo(...) #endif +#define SECTOR_SIZE ( 512 ) +#define SEC_TO_MSEC ( 1000 ) +#define MSEC_TO_USEC ( 1000 ) +#define USEC_TO_NSEC ( 1000 ) +#define SEC_TO_USEC ( 1000000 ) + // number of attributes diskstats has #define DISK_STATS_SIZE ( 11 ) // maximum size limit of a stats file @@ -266,7 +272,10 @@ 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_ALERT ( 3600 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 ) + +// UID IO threshold in bytes +#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL ) struct storaged_config { int periodic_chores_interval_unit; @@ -277,6 +286,7 @@ struct storaged_config { bool proc_uid_io_available; // whether uid_io is accessible bool emmc_available; // whether eMMC est_csd file is readable bool diskstats_available; // whether diskstats is accessible + int event_time_check_usec; // check how much cputime spent in event loop }; class storaged_t { @@ -293,21 +303,10 @@ public: storaged_t(void); ~storaged_t() {} void event(void); + void event_checked(void); void pause(void) { sleep(mConfig.periodic_chores_interval_unit); } - void set_unit_interval(int unit) { - mConfig.periodic_chores_interval_unit = unit; - } - void set_diskstats_interval(int disk_stats) { - mConfig.periodic_chores_interval_disk_stats_publish = disk_stats; - } - void set_emmc_interval(int emmc_info) { - mConfig.periodic_chores_interval_emmc_info_publish = emmc_info; - } - void set_uid_io_interval(int uid_io) { - mUidm.set_periodic_chores_interval(uid_io); - } std::vector get_tasks(void) { // There could be a race when get_tasks() and the main thread is updating at the same time // While update_running_tasks() is updating the critical sections at the end of the function diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index eceb7fd34..9f95c5188 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -46,11 +46,12 @@ class uid_monitor { private: std::unordered_map last_uids; void set_last_uids(std::unordered_map&& uids, uint64_t ts); - int interval; // monitor interval in seconds + int interval; // monitor interval in seconds + int threshold; // monitor threshold in bytes uint64_t last_report_ts; // timestamp of last report in nsec public: uid_monitor(); - void set_periodic_chores_interval(int t) { interval = t; } + 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(); void report(); diff --git a/storaged/main.cpp b/storaged/main.cpp index 915157493..c7f3dff5c 100644 --- a/storaged/main.cpp +++ b/storaged/main.cpp @@ -96,7 +96,7 @@ void* storaged_main(void* s) { LOG_TO(SYSTEM, INFO) << "storaged: Start"; for (;;) { - storaged->event(); + storaged->event_checked(); storaged->pause(); } return NULL; @@ -107,10 +107,6 @@ static void help_message(void) { printf(" -d --dump Dump task I/O usage to stdout\n"); printf(" -u --uid Dump uid I/O usage to stdout\n"); printf(" -s --start Start storaged (default)\n"); - printf(" --emmc=INTERVAL Set publish interval of emmc lifetime information (in days)\n"); - printf(" --diskstats=INTERVAL Set publish interval of diskstats (in hours)\n"); - printf(" --uidio=INTERVAL Set publish interval of uid io (in hours)\n"); - printf(" --unit=INTERVAL Set storaged's refresh interval (in seconds)\n"); fflush(stdout); } @@ -121,11 +117,6 @@ int main(int argc, char** argv) { int flag_main_service = 0; int flag_dump_task = 0; int flag_dump_uid = 0; - int flag_config = 0; - int unit_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT; - int diskstats_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH; - int emmc_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH; - int uid_io_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT; int fd_emmc = -1; int opt; @@ -136,11 +127,7 @@ int main(int argc, char** argv) { {"kill", no_argument, 0, 'k'}, {"dump", no_argument, 0, 'd'}, {"uid", no_argument, 0, 'u'}, - {"help", no_argument, 0, 'h'}, - {"unit", required_argument, 0, 0 }, - {"diskstats", required_argument, 0, 0 }, - {"emmc", required_argument, 0, 0 }, - {"uidio", required_argument, 0, 0 } + {"help", no_argument, 0, 'h'} }; opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx); if (opt == -1) { @@ -148,53 +135,6 @@ int main(int argc, char** argv) { } switch (opt) { - case 0: - printf("option %s", long_options[opt_idx].name); - if (optarg) { - printf(" with arg %s", optarg); - if (strcmp(long_options[opt_idx].name, "unit") == 0) { - unit_interval = atoi(optarg); - if (unit_interval == 0) { - fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n", - long_options[opt_idx].name); - help_message(); - return -1; - } - } else if (strcmp(long_options[opt_idx].name, "diskstats") == 0) { - diskstats_interval = atoi(optarg) * HOUR_TO_SEC; - if (diskstats_interval == 0) { - fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n", - long_options[opt_idx].name); - help_message(); - return -1; - } - - } else if (strcmp(long_options[opt_idx].name, "emmc") == 0) { - emmc_interval = atoi(optarg) * DAY_TO_SEC; - if (emmc_interval == 0) { - fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n", - long_options[opt_idx].name); - help_message(); - return -1; - } - } else if (strcmp(long_options[opt_idx].name, "uidio") == 0) { - uid_io_interval = atoi(optarg) * HOUR_TO_SEC; - if (uid_io_interval == 0) { - fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n", - long_options[opt_idx].name); - help_message(); - return -1; - } - } - flag_config = 1; - } else { - fprintf(stderr, "Invalid argument. Option %s requires an argument.\n", - long_options[opt_idx].name); - help_message(); - return -1; - } - printf("\n"); - break; case 's': flag_main_service = 1; break; @@ -225,12 +165,6 @@ int main(int argc, char** argv) { return -1; } - if (flag_config && flag_dump_task) { - fprintf(stderr, "Invalid arguments. Cannot set configs in \'dump\' option.\n"); - help_message(); - return -1; - } - if (flag_main_service) { // start main thread static const char mmc0_ext_csd[] = "/d/mmc0/mmc0:0001/ext_csd"; fd_emmc = android_get_control_file(mmc0_ext_csd); @@ -243,13 +177,6 @@ int main(int argc, char** argv) { storaged.set_privileged_fds(fd_emmc); - if (flag_config) { - storaged.set_unit_interval(unit_interval); - storaged.set_diskstats_interval(diskstats_interval); - storaged.set_emmc_interval(emmc_interval); - storaged.set_uid_io_interval(uid_io_interval); - } - // Start the main thread of storaged pthread_t storaged_main_thread; errno = pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged); diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index 0c53f4482..1950c217a 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -176,10 +177,21 @@ storaged_t::storaged_t(void) { mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); - mConfig.periodic_chores_interval_unit = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT; - mConfig.periodic_chores_interval_disk_stats_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH; - mConfig.periodic_chores_interval_emmc_info_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH; - mUidm.set_periodic_chores_interval(DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT); + mConfig.periodic_chores_interval_unit = + property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); + + mConfig.event_time_check_usec = + property_get_int32("ro.storaged.event.perf_check", 0); + + mConfig.periodic_chores_interval_disk_stats_publish = + property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); + + 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)); mStarttime = time(NULL); } @@ -212,3 +224,30 @@ void storaged_t::event(void) { mTimer += mConfig.periodic_chores_interval_unit; } + +void storaged_t::event_checked(void) { + struct timespec start_ts, end_ts; + bool check_time = true; + + if (mConfig.event_time_check_usec && + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) { + check_time = false; + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + } + + event(); + + if (mConfig.event_time_check_usec) { + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + return; + } + int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC + + (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC; + if (cost > mConfig.event_time_check_usec) { + LOG_TO(SYSTEM, ERROR) + << "event loop spent " << cost << " usec, threshold " + << mConfig.event_time_check_usec << " usec"; + } + } +} diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index 4105dae8f..2a84a0c40 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -33,8 +33,6 @@ #include "storaged.h" #include "storaged_uid_monitor.h" -static const uint64_t io_alert_threshold = 1024 * 1024 * 1024; // 1GB - using namespace android; using namespace android::base; @@ -116,7 +114,7 @@ void uid_monitor::report() 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 = io_alert_threshold * ((double)ts_delta / interval / NS_PER_SEC); + uint64_t adjusted_threshold = threshold * ((double)ts_delta / interval / NS_PER_SEC); std::unordered_map uids = get_uids(); if (uids.empty()) { diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp index 6e4ddb66c..1dcd0ffcf 100644 --- a/storaged/storaged_utils.cpp +++ b/storaged/storaged_utils.cpp @@ -41,11 +41,6 @@ #include #include -#define SECTOR_SIZE ( 512 ) -#define SEC_TO_MSEC ( 1000 ) -#define MSEC_TO_USEC ( 1000 ) -#define USEC_TO_NSEC ( 1000 ) - bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) { // Get time struct timespec ts; -- cgit v1.2.3 From 88ad33eff1fd70d276f9be70164afeb0dc639e58 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Mon, 23 Jan 2017 15:31:04 -0800 Subject: storaged: remove task io code Bug: 34612499 Change-Id: Id0599ee2ae025a186259e95363c1ddd0feae8079 --- storaged/include/storaged.h | 33 ------ storaged/include/storaged_service.h | 6 +- storaged/include/storaged_utils.h | 4 - storaged/main.cpp | 43 +------- storaged/storaged.cpp | 15 --- storaged/storaged.rc | 1 - storaged/storaged_service.cpp | 28 ----- storaged/storaged_utils.cpp | 185 ------------------------------- storaged/tests/storaged_test.cpp | 215 +----------------------------------- 9 files changed, 4 insertions(+), 526 deletions(-) diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index d3e6b7140..15d830c39 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -123,28 +123,6 @@ public: } }; -class tasks_t { -private: - FRIEND_TEST(storaged_test, tasks_t); - sem_t mSem; - // hashmap for all running tasks w/ pid as key - std::unordered_map mRunning; - // hashmap for all tasks that have been killed (categorized by cmd) w/ cmd as key - std::unordered_map mOld; - std::unordered_map get_running_tasks(); -public: - tasks_t() { - sem_init(&mSem, 0, 1); // TODO: constructor don't have a return value, what if sem_init fails - } - - ~tasks_t() { - sem_destroy(&mSem); - } - - void update_running_tasks(void); - std::vector get_tasks(void); -}; - class stream_stats { private: double mSum; @@ -282,7 +260,6 @@ struct storaged_config { int periodic_chores_interval_disk_stats_publish; int periodic_chores_interval_emmc_info_publish; int periodic_chores_interval_uid_io; - bool proc_taskio_readable; // are /proc/[pid]/{io, comm, cmdline, stat} all readable bool proc_uid_io_available; // whether uid_io is accessible bool emmc_available; // whether eMMC est_csd file is readable bool diskstats_available; // whether diskstats is accessible @@ -296,7 +273,6 @@ private: disk_stats_publisher mDiskStats; disk_stats_monitor mDsm; emmc_info_t mEmmcInfo; - tasks_t mTasks; uid_monitor mUidm; time_t mStarttime; public: @@ -307,15 +283,6 @@ public: void pause(void) { sleep(mConfig.periodic_chores_interval_unit); } - std::vector get_tasks(void) { - // There could be a race when get_tasks() and the main thread is updating at the same time - // While update_running_tasks() is updating the critical sections at the end of the function - // all together atomically, the final state of task_t can only be either the main thread's - // update or this update. Since the race can only occur when both threads are updating - // "simultaneously", either final state is acceptable. - mTasks.update_running_tasks(); - return mTasks.get_tasks(); - } void set_privileged_fds(int fd_emmc) { mEmmcInfo.set_emmc_fd(fd_emmc); diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h index 220038c23..0735f292d 100644 --- a/storaged/include/storaged_service.h +++ b/storaged/include/storaged_service.h @@ -30,11 +30,9 @@ using namespace android; class IStoraged : public IInterface { public: enum { - DUMPTASKS = IBinder::FIRST_CALL_TRANSACTION, - DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION + 1, + DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION, }; // Request the service to run the test function - virtual std::vector dump_tasks(const char* option) = 0; virtual std::vector dump_uids(const char* option) = 0; DECLARE_META_INTERFACE(Storaged); @@ -44,7 +42,6 @@ public: class BpStoraged : public BpInterface { public: BpStoraged(const sp& impl) : BpInterface(impl){}; - virtual std::vector dump_tasks(const char* option); virtual std::vector dump_uids(const char* option); }; @@ -54,7 +51,6 @@ class BnStoraged : public BnInterface { }; class Storaged : public BnStoraged { - virtual std::vector dump_tasks(const char* option); virtual std::vector dump_uids(const char* option); }; diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h index bb14708c5..2161c4008 100644 --- a/storaged/include/storaged_utils.h +++ b/storaged/include/storaged_utils.h @@ -31,14 +31,10 @@ struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* void add_disk_stats(struct disk_stats* src, struct disk_stats* dst); bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info); -// Task I/O -bool parse_task_info(uint32_t pid, struct task_info* info); -void sort_running_tasks_info(std::vector &tasks); // UID I/O void sort_running_uids_info(std::vector &uids); // Logging -void log_console_running_tasks_info(std::vector tasks); void log_console_running_uids_info(std::vector uids); void log_debug_disk_perf(struct disk_perf* perf, const char* type); diff --git a/storaged/main.cpp b/storaged/main.cpp index c7f3dff5c..9ad420e54 100644 --- a/storaged/main.cpp +++ b/storaged/main.cpp @@ -61,8 +61,7 @@ static int drop_privs() { if (cap_clear(caps.get()) < 0) return -1; cap_value_t cap_value[] = { CAP_SETGID, - CAP_SETUID, - CAP_SYS_PTRACE // allow access to proc//io as non-root user + CAP_SETUID }; if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(cap_value), cap_value, @@ -73,10 +72,6 @@ static int drop_privs() { if (cap_set_proc(caps.get()) < 0) return -1; - gid_t groups[] = { AID_READPROC }; - - if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) return -1; - if (setgid(AID_SYSTEM) != 0) return -1; if (setuid(AID_SYSTEM) != 0) return -1; @@ -104,7 +99,6 @@ void* storaged_main(void* s) { static void help_message(void) { printf("usage: storaged [OPTION]\n"); - printf(" -d --dump Dump task I/O usage to stdout\n"); printf(" -u --uid Dump uid I/O usage to stdout\n"); printf(" -s --start Start storaged (default)\n"); fflush(stdout); @@ -115,7 +109,6 @@ static void help_message(void) { int main(int argc, char** argv) { int flag_main_service = 0; - int flag_dump_task = 0; int flag_dump_uid = 0; int fd_emmc = -1; int opt; @@ -125,7 +118,6 @@ int main(int argc, char** argv) { static struct option long_options[] = { {"start", no_argument, 0, 's'}, {"kill", no_argument, 0, 'k'}, - {"dump", no_argument, 0, 'd'}, {"uid", no_argument, 0, 'u'}, {"help", no_argument, 0, 'h'} }; @@ -138,9 +130,6 @@ int main(int argc, char** argv) { case 's': flag_main_service = 1; break; - case 'd': - flag_dump_task = 1; - break; case 'u': flag_dump_uid = 1; break; @@ -159,7 +148,7 @@ int main(int argc, char** argv) { flag_main_service = 1; } - if (flag_main_service && flag_dump_task) { + if (flag_main_service && flag_dump_uid) { fprintf(stderr, "Invalid arguments. Option \"start\" and \"dump\" cannot be used together.\n"); help_message(); return -1; @@ -195,34 +184,6 @@ int main(int argc, char** argv) { return 0; } - if (flag_dump_task) { - sp storaged_service = get_storaged_service(); - if (storaged_service == NULL) { - fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n"); - return -1; - } - std::vector res = storaged_service->dump_tasks(NULL); - - if (res.size() == 0) { - fprintf(stderr, "Task I/O is not readable in this version of kernel.\n"); - return 0; - } - - time_t starttime = storaged.get_starttime(); - - if (starttime == (time_t)-1) { - fprintf(stderr, "Unknown start time\n"); - } else { - char* time_str = ctime(&starttime); - printf("Application I/O was collected by storaged since %s", time_str); - } - - sort_running_tasks_info(res); - log_console_running_tasks_info(res); - - return 0; - } - if (flag_dump_uid) { sp storaged_service = get_storaged_service(); if (storaged_service == NULL) { diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index 1950c217a..d3fa2b97d 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -166,15 +166,6 @@ storaged_t::storaged_t(void) { mConfig.diskstats_available = true; } - mConfig.proc_taskio_readable = true; - const char* test_paths[] = {"/proc/1/io", "/proc/1/comm", "/proc/1/cmdline", "/proc/1/stat"}; - for (uint i = 0; i < sizeof(test_paths) / sizeof(const char*); ++i) { - if (access(test_paths[i], R_OK) < 0) { - mConfig.proc_taskio_readable = false; - break; - } - } - mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); mConfig.periodic_chores_interval_unit = @@ -205,12 +196,6 @@ void storaged_t::event(void) { } } -#ifdef DEBUG - if (mConfig.proc_taskio_readable) { - mTasks.update_running_tasks(); - } -#endif - if (mConfig.emmc_available && mTimer && (mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) { mEmmcInfo.update(); diff --git a/storaged/storaged.rc b/storaged/storaged.rc index a8fa5a799..53fdb85f5 100644 --- a/storaged/storaged.rc +++ b/storaged/storaged.rc @@ -1,5 +1,4 @@ service storaged /system/bin/storaged class main file /d/mmc0/mmc0:0001/ext_csd r - group root readproc writepid /dev/cpuset/system-background/tasks diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp index 2a81aef65..15185ec6f 100644 --- a/storaged/storaged_service.cpp +++ b/storaged/storaged_service.cpp @@ -29,20 +29,6 @@ extern storaged_t storaged; -std::vector BpStoraged::dump_tasks(const char* /*option*/) { - Parcel data, reply; - data.writeInterfaceToken(IStoraged::getInterfaceDescriptor()); - - remote()->transact(DUMPTASKS, data, &reply); - - uint32_t res_size = reply.readInt32(); - std::vector res(res_size); - for (auto&& task : res) { - reply.read(&task, sizeof(task)); - } - return res; -} - std::vector BpStoraged::dump_uids(const char* /*option*/) { Parcel data, reply; data.writeInterfaceToken(IStoraged::getInterfaceDescriptor()); @@ -65,16 +51,6 @@ status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply data.checkInterface(this); switch(code) { - case DUMPTASKS: { - std::vector res = dump_tasks(NULL); - - reply->writeInt32(res.size()); - for (auto task : res) { - reply->write(&task, sizeof(task)); - } - return NO_ERROR; - } - break; case DUMPUIDS: { std::vector res = dump_uids(NULL); reply->writeInt32(res.size()); @@ -91,10 +67,6 @@ status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply } } -std::vector Storaged::dump_tasks(const char* /* option */) { - return storaged.get_tasks(); -} - std::vector Storaged::dump_uids(const char* /* option */) { std::vector uids_v; std::unordered_map uids_m = storaged.get_uids(); diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp index 1dcd0ffcf..51ea64fdd 100644 --- a/storaged/storaged_utils.cpp +++ b/storaged/storaged_utils.cpp @@ -245,191 +245,6 @@ bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) { return true; } -#define PROC_DIR "/proc/" -#define PROC_STAT_STARTTIME_IDX ( 22 ) // This index is 1 based according to the linux proc man page -bool parse_task_info(uint32_t pid, struct task_info* info) { - std::string buffer; - std::string pid_str = std::to_string(pid); - info->pid = pid; - - // Get task I/O - std::string task_io_path = android::base::StringPrintf(PROC_DIR "%s/io", pid_str.c_str()); - if (!android::base::ReadFileToString(task_io_path, &buffer)) return false; - - std::stringstream ss(buffer); - std::string title; - - ss >> title >> info->rchar - >> title >> info->wchar - >> title >> info->syscr - >> title >> info->syscw - >> title >> info->read_bytes - >> title >> info->write_bytes - >> title >> info->cancelled_write_bytes; - ss.clear(); - - // Get cmd string - std::string task_cmdline_path = android::base::StringPrintf(PROC_DIR "%u/cmdline", pid); - if (!android::base::ReadFileToString(task_cmdline_path, &buffer)) return false; - strlcpy(info->cmd, android::base::Trim(buffer).c_str(), sizeof(info->cmd)); - - if (info->cmd[0] == '\0') { - std::string task_comm_path = android::base::StringPrintf(PROC_DIR "%u/comm", pid); - if (!android::base::ReadFileToString(task_comm_path, &buffer)) return false; - strlcpy(info->cmd, android::base::Trim(buffer).c_str(), sizeof(info->cmd)); - } - - // Get task start time - std::string task_stat_path = android::base::StringPrintf(PROC_DIR "%u/stat", pid); - if (!android::base::ReadFileToString(task_stat_path, &buffer)) return false; - - std::vector stat_parts = android::base::Split(buffer, " "); - info->starttime = atoll(stat_parts[PROC_STAT_STARTTIME_IDX - 1].c_str()); - - return true; -} - -static bool is_pid(char* d_name) { - if (!d_name || d_name[0] == '\0') return false; - char* c = d_name; - while (*c) { - if (!isdigit(*c)) return false; - ++c; - } - return true; -} - -static bool cmp_task_info(struct task_info i, struct task_info j) { - if (i.write_bytes + i.read_bytes != j.write_bytes + j.read_bytes) { - return i.write_bytes + i.read_bytes > j.write_bytes + j.read_bytes; - } - if (i.wchar + i.rchar != j.wchar + j.rchar) { - return i.wchar + i.rchar > j.wchar + j.rchar; - } - if (i.syscw + i.syscr != j.syscw + j.syscr) { - return i.syscw + i.syscr > j.syscw + j.syscr; - } - - return strcmp(i.cmd, j.cmd) < 0; -} - -std::unordered_map tasks_t::get_running_tasks() { - std::unordered_map retval; - std::unique_ptr dir(opendir(PROC_DIR), closedir); - CHECK(dir != NULL); - struct dirent* dp; - - for (;;) { - if ((dp = readdir(dir.get())) == NULL) break; - if (!is_pid(dp->d_name)) continue; - - uint32_t pid = atol(dp->d_name); - struct task_info info; - if (parse_task_info(pid, &info)) { - retval[pid] = info; - } - } - return retval; -} - -static void add_task_info(struct task_info* src, struct task_info* dst) { - CHECK(strcmp(src->cmd, dst->cmd) == 0); - - dst->pid = 0; - dst->rchar += src->rchar; - dst->wchar += src->wchar; - dst->syscr += src->syscr; - dst->syscw += src->syscw; - dst->read_bytes += src->read_bytes; - dst->write_bytes += src->write_bytes; - dst->cancelled_write_bytes += src->cancelled_write_bytes; - dst->starttime = 0; -} - -void tasks_t::update_running_tasks(void) { - std::unordered_map tasks_latest = get_running_tasks(); - std::unordered_map tasks_old = mOld; - - for (auto t : mRunning) { - uint32_t pid = t.first; - // old task on mRunning still exist on tasks_latest - if (tasks_latest.find(pid) != tasks_latest.end() && - tasks_latest[pid].starttime == t.second.starttime) { - continue; - } else { - // This branch will handle 2 cases: - // - Task get killed between the 2 samplings - // - Task get killed and its pid is reused - std::string cmd = t.second.cmd; - struct task_info info = t.second; - - if (tasks_old.find(cmd) == tasks_old.end()) { - tasks_old[cmd] = info; - } else { - add_task_info(&info, &tasks_old[cmd]); - } - } - } - { // update critical area - // this is really fast! - std::unique_ptr lock(new lock_t(&mSem)); - mRunning = tasks_latest; - mOld = tasks_old; - } - -} - -std::vector tasks_t::get_tasks(void) { - std::unique_ptr lock(new lock_t(&mSem)); - std::unordered_map tasks_map = mOld; - - for (auto i : mRunning) { - std::string cmd = i.second.cmd; - if (tasks_map.find(cmd) == tasks_map.end()) { - tasks_map[cmd] = i.second; - } else { - add_task_info(&i.second, &tasks_map[cmd]); - } - } - - std::vector retval(tasks_map.size()); - int idx = 0; - for (auto i : tasks_map) { - retval[idx++] = i.second; - } - - return retval; -} - -void sort_running_tasks_info(std::vector &tasks) { - std::sort(tasks.begin(), tasks.end(), cmp_task_info); -} - -/* Logging functions */ -void log_console_running_tasks_info(std::vector tasks) { -// Sample Output: -// Application Read Write Read Write Read Write Cancelled -// Name Characters Characters Syscalls Syscalls Bytes Bytes Writebytes -// ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- -// zygote64 37688308 3388467 7607 4363 314519552 5373952 8192 -// system_server 95874193 2216913 74613 52257 213078016 7237632 16384 -// zygote 506279 1726194 921 263 128114688 1765376 0 -// /vendor/bin/qcks 75415632 75154382 21672 25036 63627264 29974528 10485760 -// /init 86658523 5107871 82113 8633 91015168 1245184 0 - - // Title - printf(" Application Read Write Read Write Read Write Cancelled\n" - " Name Characters Characters Syscalls Syscalls Bytes Bytes Writebytes\n" - " ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------\n"); - - for (struct task_info task : tasks) { - printf("%50s%15ju%15ju%15ju%15ju%15ju%15ju%15ju\n", - task.cmd, task.rchar, task.wchar, task.syscr, task.syscw, - task.read_bytes, task.write_bytes, task.cancelled_write_bytes); - } - fflush(stdout); -} - 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--) { diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index 99b21ac0f..5395b9a41 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -30,7 +30,6 @@ #define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" #define SDA_DISK_STATS_PATH "/sys/block/sda/stat" #define EMMC_EXT_CSD_PATH "/d/mmc0/mmc0:0001/ext_csd" -#define INIT_TASK_IO_PATH "/proc/1/io" static void pause(uint32_t sec) { const char* path = "/cache/test"; @@ -144,46 +143,6 @@ TEST(storaged_test, emmc_info) { } } -TEST(storaged_test, task_info) { - // parse_task_info should read something other than 0 from /proc/1/* - struct task_info task_info; - memset(&task_info, 0, sizeof(task_info)); - - if (!parse_task_info(1, &task_info)) return; - - EXPECT_EQ((uint32_t)1, task_info.pid); - EXPECT_LT((uint64_t)0, task_info.rchar); - EXPECT_LT((uint64_t)0, task_info.wchar); - EXPECT_LT((uint64_t)0, task_info.syscr); - EXPECT_LT((uint64_t)0, task_info.syscw); - EXPECT_LT((uint64_t)0, task_info.read_bytes); - EXPECT_LT((uint64_t)0, task_info.write_bytes); - // cancelled_write_bytes of init could be 0, there is no need to test - EXPECT_LE((uint64_t)0, task_info.starttime); - EXPECT_NE((char*)NULL, strstr(task_info.cmd, "init")); - - // Entries in /proc/1/io should be increasing through time - struct task_info task_old, task_new; - memset(&task_old, 0, sizeof(task_old)); - memset(&task_new, 0, sizeof(task_new)); - - // parse_task_info should succeed at this point - ASSERT_TRUE(parse_task_info(1, &task_old)); - sleep(1); - ASSERT_TRUE(parse_task_info(1, &task_new)); - - EXPECT_EQ(task_old.pid, task_new.pid); - EXPECT_LE(task_old.rchar, task_new.rchar); - EXPECT_LE(task_old.wchar, task_new.wchar); - EXPECT_LE(task_old.syscr, task_new.syscr); - EXPECT_LE(task_old.syscw, task_new.syscw); - EXPECT_LE(task_old.read_bytes, task_new.read_bytes); - EXPECT_LE(task_old.write_bytes, task_new.write_bytes); - EXPECT_LE(task_old.cancelled_write_bytes, task_new.cancelled_write_bytes); - EXPECT_EQ(task_old.starttime, task_new.starttime); - EXPECT_EQ(0, strcmp(task_old.cmd, task_new.cmd)); -} - static double mean(std::deque nums) { double sum = 0.0; for (uint32_t i : nums) { @@ -244,179 +203,6 @@ TEST(storaged_test, stream_stats) { } } -static void expect_increasing(struct task_info told, struct task_info tnew) { - ASSERT_EQ(told.pid, tnew.pid); - ASSERT_EQ(told.starttime, tnew.starttime); - ASSERT_EQ(strcmp(told.cmd, tnew.cmd), 0); - - EXPECT_LE(told.rchar, tnew.rchar); - EXPECT_LE(told.wchar, tnew.wchar); - EXPECT_LE(told.syscr, tnew.syscr); - EXPECT_LE(told.syscw, tnew.syscw); - EXPECT_LE(told.read_bytes, tnew.read_bytes); - EXPECT_LE(told.write_bytes, tnew.write_bytes); - EXPECT_LE(told.cancelled_write_bytes, tnew.cancelled_write_bytes); -} - -static void expect_equal(struct task_info told, struct task_info tnew) { - ASSERT_EQ(told.pid, tnew.pid); - ASSERT_EQ(told.starttime, tnew.starttime); - ASSERT_EQ(strcmp(told.cmd, tnew.cmd), 0); - - EXPECT_EQ(told.rchar, tnew.rchar); - EXPECT_EQ(told.wchar, tnew.wchar); - EXPECT_EQ(told.syscr, tnew.syscr); - EXPECT_EQ(told.syscw, tnew.syscw); - EXPECT_EQ(told.read_bytes, tnew.read_bytes); - EXPECT_EQ(told.write_bytes, tnew.write_bytes); - EXPECT_EQ(told.cancelled_write_bytes, tnew.cancelled_write_bytes); -} - -static std::set find_overlap(std::unordered_map t1, - std::unordered_map t2) { - std::set retval; - for (auto i : t1) { - if (t2.find(i.first) != t2.end()) { - retval.insert(i.first); - } - } - - return retval; -} - -static std::set find_overlap(std::unordered_map t1, - std::unordered_map t2) { - std::set retval; - for (auto i : t1) { - if (t2.find(i.first) != t2.end()) { - retval.insert(i.first); - } - } - - return retval; -} - -static bool cmp_app_name(struct task_info i, struct task_info j) { - return strcmp(i.cmd, j.cmd) > 0; -} - -static void expect_match(std::vector v1, std::vector v2) { - ASSERT_EQ(v1.size(), v2.size()); - std::sort(v1.begin(), v1.end(), cmp_app_name); - std::sort(v2.begin(), v2.end(), cmp_app_name); - - for (uint i = 0; i < v1.size(); ++i) { - expect_equal(v1[i], v2[i]); - } -} - -static void add_task_info(struct task_info* src, struct task_info* dst) { - ASSERT_EQ(0, strcmp(src->cmd, dst->cmd)); - - dst->pid = 0; - dst->rchar += src->rchar; - dst->wchar += src->wchar; - dst->syscr += src->syscr; - dst->syscw += src->syscw; - dst->read_bytes += src->read_bytes; - dst->write_bytes += src->write_bytes; - dst->cancelled_write_bytes += src->cancelled_write_bytes; - dst->starttime = 0; -} - -static std::vector -categorize_tasks(std::unordered_map tasks) { - std::unordered_map tasks_cmd; - for (auto i : tasks) { - std::string cmd = i.second.cmd; - if (tasks_cmd.find(cmd) == tasks_cmd.end()) { - tasks_cmd[cmd] = i.second; - } else { - add_task_info(&i.second, &tasks_cmd[cmd]); - } - } - - std::vector retval(tasks_cmd.size()); - int cnt = 0; - for (auto i : tasks_cmd) { - retval[cnt++] = i.second; - } - - return retval; -} - -#define TEST_LOOPS 20 -TEST(storaged_test, tasks_t) { - // pass this test if /proc/[pid]/io is not readable - const char* test_paths[] = {"/proc/1/io", "/proc/1/comm", "/proc/1/cmdline", "/proc/1/stat"}; - for (uint i = 0; i < sizeof(test_paths) / sizeof(const char*); ++i) { - if (access(test_paths[i], R_OK) < 0) return; - } - - tasks_t tasks; - EXPECT_EQ((uint32_t)0, tasks.mRunning.size()); - EXPECT_EQ((uint32_t)0, tasks.mOld.size()); - - tasks.update_running_tasks(); - - std::unordered_map prev_running = tasks.mRunning; - std::unordered_map prev_old = tasks.mOld; - - // hashmap maintaining - std::unordered_map tasks_pid = tasks.mRunning; - - // get_running_tasks() should return something other than a null map - std::unordered_map test = tasks.get_running_tasks(); - EXPECT_LE((uint32_t)1, test.size()); - - for (int i = 0; i < TEST_LOOPS; ++i) { - tasks.update_running_tasks(); - - std::set overlap_running = find_overlap(prev_running, tasks.mRunning); - std::set overlap_old = find_overlap(prev_old, tasks.mOld); - - // overlap_running should capture init(pid == 1), since init never get killed - EXPECT_LE((uint32_t)1, overlap_running.size()); - EXPECT_NE(overlap_running.find((uint32_t)1), overlap_running.end()); - // overlap_old should never capture init, since init never get killed - EXPECT_EQ(overlap_old.find("init"), overlap_old.end()); - - // overlapping entries in previous and current running-tasks map should have increasing contents - for (uint32_t i : overlap_running) { - expect_increasing(prev_running[i], tasks.mRunning[i]); - } - - // overlapping entries in previous and current killed-tasks map should have increasing contents - // and the map size should also be increasing - for (std::string i : overlap_old) { - expect_increasing(prev_old[i], tasks.mOld[i]); - } - EXPECT_LE(prev_old.size(), tasks.mRunning.size()); - - // update app name & tasks_pid - for (auto i : tasks.mRunning) { - // test will fail if the pid got wrapped - if (tasks_pid.find(i.first) != tasks_pid.end()) { - expect_increasing(tasks_pid[i.first], i.second); - tasks_pid[i.first] = i.second; - } else { - tasks_pid[i.first] = i.second; - } - } - - // get maintained tasks - std::vector test_tasks = categorize_tasks(tasks_pid); - std::vector real_tasks = tasks.get_tasks(); - - expect_match(test_tasks, real_tasks); - - prev_running = tasks.mRunning; - prev_old = tasks.mOld; - - pause(5); - } -} - static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) { struct disk_perf retval; retval.read_perf = (double)perf.read_perf * mul; @@ -569,6 +355,7 @@ static void expect_increasing(struct disk_stats stats1, struct disk_stats stats2 EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue); } +#define TEST_LOOPS 20 TEST(storaged_test, disk_stats_publisher) { // asserting that there is one file for diskstats ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0); -- cgit v1.2.3