storaged: clean up disk stats code
Merged disk_stats_publisher into disk_stats_monitor class.
Moved proc file check to disk_stats class instead of doing so in
storaged, same for uid_io.
Added is_zero function to check zero disk_stats.
Added operators to compute disk_stats.
Change-Id: I277ae51f6fe18464f92e45c03471343784e67093
diff --git a/storaged/Android.bp b/storaged/Android.bp
index 25b433c..6aef8c8 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -44,6 +44,7 @@
srcs: [
"storaged.cpp",
+ "storaged_diskstats.cpp",
"storaged_info.cpp",
"storaged_service.cpp",
"storaged_utils.cpp",
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index bd99361..28de7c9 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -29,23 +29,15 @@
#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#define FRIEND_TEST(test_case_name, test_name) \
+friend class test_case_name##_##test_name##_Test
+
+#include "storaged_diskstats.h"
#include "storaged_info.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
-
-/* For debug */
-#ifdef DEBUG
-#define debuginfo(fmt, ...) \
- do {printf("%s():\t" fmt "\t[%s:%d]\n", __FUNCTION__, ##__VA_ARGS__, __FILE__, __LINE__);} \
- while(0)
-#else
-#define debuginfo(...)
-#endif
-
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define SECTOR_SIZE ( 512 )
@@ -56,162 +48,6 @@
#define HOUR_TO_SEC ( 3600 )
#define DAY_TO_SEC ( 3600 * 24 )
-// number of attributes diskstats has
-#define DISK_STATS_SIZE ( 11 )
-// maximum size limit of a stats file
-#define DISK_STATS_FILE_MAX_SIZE ( 256 )
-#define DISK_STATS_IO_IN_FLIGHT_IDX ( 8 )
-struct disk_stats {
- /* It will be extremely unlikely for any of the following entries to overflow.
- * For read_bytes(which will be greater than any of the following entries), it
- * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which
- * is the peak memory transfer rate for current memory.
- * The diskstats entries (first 11) need to be at top in this structure _after_
- * compiler's optimization.
- */
- uint64_t read_ios; // number of read I/Os processed
- uint64_t read_merges; // number of read I/Os merged with in-queue I/Os
- uint64_t read_sectors; // number of sectors read
- uint64_t read_ticks; // total wait time for read requests
- uint64_t write_ios; // number of write I/Os processed
- uint64_t write_merges; // number of write I/Os merged with in-queue I/Os
- uint64_t write_sectors; // number of sectors written
- uint64_t write_ticks; // total wait time for write requests
- uint64_t io_in_flight; // number of I/Os currently in flight
- uint64_t io_ticks; // total time this block device has been active
- uint64_t io_in_queue; // total wait time for all requests
-
- uint64_t start_time; // monotonic time accounting starts
- uint64_t end_time; // monotonic time accounting ends
- uint32_t counter; // private counter for accumulate calculations
- double io_avg; // average io_in_flight for accumulate calculations
-};
-
-
-
-struct disk_perf {
- uint32_t read_perf; // read speed (kbytes/s)
- uint32_t read_ios; // read I/Os per second
- uint32_t write_perf; // write speed (kbytes/s)
- uint32_t write_ios; // write I/Os per second
- uint32_t queue; // I/Os in queue
-};
-
-class lock_t {
- sem_t* mSem;
-public:
- lock_t(sem_t* sem) {
- mSem = sem;
- sem_wait(mSem);
- }
- ~lock_t() {
- sem_post(mSem);
- }
-};
-
-class stream_stats {
-private:
- double mSum;
- double mSquareSum;
- uint32_t mCnt;
-public:
- stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
- ~stream_stats() {};
- double get_mean() {
- return mSum / mCnt;
- }
- double get_std() {
- return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
- }
- void add(uint32_t num) {
- mSum += (double)num;
- mSquareSum += (double)num * (double)num;
- mCnt++;
- }
- void evict(uint32_t num) {
- if (mSum < num || mSquareSum < (double)num * (double)num) return;
- mSum -= (double)num;
- mSquareSum -= (double)num * (double)num;
- mCnt--;
- }
-};
-
-#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
-#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
-#define EMMC_ECSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
-#define UID_IO_STATS_PATH "/proc/uid_io/stats"
-
-class disk_stats_monitor {
-private:
- FRIEND_TEST(storaged_test, disk_stats_monitor);
- const char* DISK_STATS_PATH;
- struct disk_stats mPrevious;
- struct disk_stats mAccumulate;
- bool mStall;
- std::queue<struct disk_perf> mBuffer;
- struct {
- stream_stats read_perf; // read speed (bytes/s)
- stream_stats read_ios; // read I/Os per second
- stream_stats write_perf; // write speed (bytes/s)
- stream_stats write_ios; // write I/O per second
- stream_stats queue; // I/Os in queue
- } mStats;
- bool mValid;
- const uint32_t mWindow;
- const double mSigma;
- struct disk_perf mMean;
- struct disk_perf mStd;
-
- void update_mean();
- void update_std();
- void add(struct disk_perf* perf);
- void evict(struct disk_perf* perf);
- bool detect(struct disk_perf* perf);
-
- void update(struct disk_stats* stats);
-
-public:
- disk_stats_monitor(uint32_t window_size = 5, double sigma = 1.0) :
- mStall(false),
- mValid(false),
- mWindow(window_size),
- mSigma(sigma) {
- memset(&mPrevious, 0, sizeof(mPrevious));
- memset(&mMean, 0, sizeof(mMean));
- memset(&mStd, 0, sizeof(mStd));
-
- if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
- DISK_STATS_PATH = MMC_DISK_STATS_PATH;
- } else {
- DISK_STATS_PATH = SDA_DISK_STATS_PATH;
- }
- }
- void update(void);
-};
-
-class disk_stats_publisher {
-private:
- FRIEND_TEST(storaged_test, disk_stats_publisher);
- const char* DISK_STATS_PATH;
- struct disk_stats mAccumulate;
- struct disk_stats mPrevious;
-public:
- disk_stats_publisher(void) {
- memset(&mAccumulate, 0, sizeof(struct disk_stats));
- memset(&mPrevious, 0, sizeof(struct disk_stats));
-
- if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
- DISK_STATS_PATH = MMC_DISK_STATS_PATH;
- } else {
- DISK_STATS_PATH = SDA_DISK_STATS_PATH;
- }
- }
-
- ~disk_stats_publisher(void) {}
- void publish(void);
- void update(void);
-};
-
// Periodic chores intervals in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
@@ -225,8 +61,6 @@
int periodic_chores_interval_unit;
int periodic_chores_interval_disk_stats_publish;
int periodic_chores_interval_uid_io;
- bool proc_uid_io_available; // whether uid_io is accessible
- bool diskstats_available; // whether diskstats is accessible
int event_time_check_usec; // check how much cputime spent in event loop
};
@@ -235,7 +69,6 @@
private:
time_t mTimer;
storaged_config mConfig;
- disk_stats_publisher mDiskStats;
disk_stats_monitor mDsm;
uid_monitor mUidm;
time_t mStarttime;
diff --git a/storaged/include/storaged_diskstats.h b/storaged/include/storaged_diskstats.h
new file mode 100644
index 0000000..ff030f6
--- /dev/null
+++ b/storaged/include/storaged_diskstats.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _STORAGED_DISKSTATS_H_
+#define _STORAGED_DISKSTATS_H_
+
+#include <stdint.h>
+
+// number of attributes diskstats has
+#define DISK_STATS_SIZE ( 11 )
+
+#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
+#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
+
+struct disk_stats {
+ /* It will be extremely unlikely for any of the following entries to overflow.
+ * For read_bytes(which will be greater than any of the following entries), it
+ * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which
+ * is the peak memory transfer rate for current memory.
+ * The diskstats entries (first 11) need to be at top in this structure _after_
+ * compiler's optimization.
+ */
+ uint64_t read_ios; // number of read I/Os processed
+ uint64_t read_merges; // number of read I/Os merged with in-queue I/Os
+ uint64_t read_sectors; // number of sectors read
+ uint64_t read_ticks; // total wait time for read requests
+ uint64_t write_ios; // number of write I/Os processed
+ uint64_t write_merges; // number of write I/Os merged with in-queue I/Os
+ uint64_t write_sectors; // number of sectors written
+ uint64_t write_ticks; // total wait time for write requests
+ uint64_t io_in_flight; // number of I/Os currently in flight
+ uint64_t io_ticks; // total time this block device has been active
+ uint64_t io_in_queue; // total wait time for all requests
+
+ uint64_t start_time; // monotonic time accounting starts
+ uint64_t end_time; // monotonic time accounting ends
+ uint32_t counter; // private counter for accumulate calculations
+ double io_avg; // average io_in_flight for accumulate calculations
+
+ bool is_zero() {
+ return read_ios == 0 && write_ios == 0 &&
+ io_in_flight == 0 && io_ticks == 0 && io_in_queue == 0;
+ }
+
+ friend disk_stats operator- (disk_stats curr, const disk_stats& prev) {
+ curr.read_ios -= prev.read_ios;
+ curr.read_merges -= prev.read_merges;
+ curr.read_sectors -= prev.read_sectors;
+ curr.read_ticks -= prev.read_ticks;
+ curr.write_ios -= prev.write_ios;
+ curr.write_merges -= prev.write_merges;
+ curr.write_sectors -= prev.write_sectors;
+ curr.write_ticks -= prev.write_ticks;
+ /* skips io_in_flight, use current value */
+ curr.io_ticks -= prev.io_ticks;
+ curr.io_in_queue -= prev.io_in_queue;
+ return curr;
+ }
+
+ friend bool operator== (const disk_stats& a, const disk_stats& b) {
+ return a.read_ios == b.read_ios &&
+ a.read_merges == b.read_merges &&
+ a.read_sectors == b.read_sectors &&
+ a.read_ticks == b.read_ticks &&
+ a.write_ios == b.write_ios &&
+ a.write_merges == b.write_merges &&
+ a.write_sectors == b.write_sectors &&
+ a.write_ticks == b.write_ticks &&
+ /* skips io_in_flight */
+ a.io_ticks == b.io_ticks &&
+ a.io_in_queue == b.io_in_queue;
+ }
+
+ disk_stats& operator+= (const disk_stats& stats) {
+ read_ios += stats.read_ios;
+ read_merges += stats.read_merges;
+ read_sectors += stats.read_sectors;
+ read_ticks += stats.read_ticks;
+ write_ios += stats.write_ios;
+ write_merges += stats.write_merges;
+ write_sectors += stats.write_sectors;
+ write_ticks += stats.write_ticks;
+ /* skips io_in_flight, use current value */
+ io_ticks += stats.io_ticks;
+ io_in_queue += stats.io_in_queue;
+ return *this;
+ }
+};
+
+struct disk_perf {
+ uint32_t read_perf; // read speed (kbytes/s)
+ uint32_t read_ios; // read I/Os per second
+ uint32_t write_perf; // write speed (kbytes/s)
+ uint32_t write_ios; // write I/Os per second
+ uint32_t queue; // I/Os in queue
+ bool is_zero() {
+ return read_perf == 0 && read_ios == 0 &&
+ write_perf == 0 && write_ios == 0 && queue == 0;
+ }
+};
+
+class stream_stats {
+private:
+ double mSum;
+ double mSquareSum;
+ uint32_t mCnt;
+public:
+ stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
+ ~stream_stats() {};
+ double get_mean() {
+ return mSum / mCnt;
+ }
+ double get_std() {
+ return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
+ }
+ void add(uint32_t num) {
+ mSum += (double)num;
+ mSquareSum += (double)num * (double)num;
+ mCnt++;
+ }
+ void evict(uint32_t num) {
+ if (mSum < num || mSquareSum < (double)num * (double)num) return;
+ mSum -= (double)num;
+ mSquareSum -= (double)num * (double)num;
+ mCnt--;
+ }
+};
+
+class disk_stats_monitor {
+private:
+ FRIEND_TEST(storaged_test, disk_stats_monitor);
+ const char* const DISK_STATS_PATH;
+ struct disk_stats mPrevious;
+ struct disk_stats mAccumulate; /* reset after stall */
+ struct disk_stats mAccumulate_pub; /* reset after publish */
+ bool mStall;
+ std::queue<struct disk_perf> mBuffer;
+ struct {
+ stream_stats read_perf; // read speed (bytes/s)
+ stream_stats read_ios; // read I/Os per second
+ stream_stats write_perf; // write speed (bytes/s)
+ stream_stats write_ios; // write I/O per second
+ stream_stats queue; // I/Os in queue
+ } mStats;
+ bool mValid;
+ const uint32_t mWindow;
+ const double mSigma;
+ struct disk_perf mMean;
+ struct disk_perf mStd;
+
+ void update_mean();
+ void update_std();
+ void add(struct disk_perf* perf);
+ void evict(struct disk_perf* perf);
+ bool detect(struct disk_perf* perf);
+
+ void update(struct disk_stats* stats);
+
+public:
+ disk_stats_monitor(uint32_t window_size = 5, double sigma = 1.0) :
+ DISK_STATS_PATH(access(MMC_DISK_STATS_PATH, R_OK) ?
+ (access(SDA_DISK_STATS_PATH, R_OK) ?
+ nullptr :
+ SDA_DISK_STATS_PATH) :
+ MMC_DISK_STATS_PATH),
+ mPrevious(), mAccumulate(), mAccumulate_pub(),
+ mStall(false), mValid(false),
+ mWindow(window_size), mSigma(sigma),
+ mMean(), mStd() {}
+ bool enabled() {
+ return DISK_STATS_PATH != nullptr;
+ }
+ void update(void);
+ void publish(void);
+};
+
+#endif /* _STORAGED_DISKSTATS_H_ */
\ No newline at end of file
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index 86d3c28..c005c4c 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -85,6 +85,18 @@
std::vector<struct uid_record> entries;
};
+class lock_t {
+ sem_t* mSem;
+public:
+ lock_t(sem_t* sem) {
+ mSem = sem;
+ sem_wait(mSem);
+ }
+ ~lock_t() {
+ sem_post(mSem);
+ }
+};
+
class uid_monitor {
private:
// last dump from /proc/uid_io/stats, uid -> uid_info
@@ -99,6 +111,8 @@
sem_t um_lock;
// start time for IO records
uint64_t start_ts;
+ // true if UID_IO_STATS_PATH is accessible
+ const bool enable;
// protobuf file for io_history
static const std::string io_history_proto_file;
@@ -126,6 +140,7 @@
// called by battery properties listener
void set_charger_state(charger_stat_t stat);
// called by storaged periodic_chore or dump with force_report
+ bool enabled() { return enable; };
void report();
};
diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h
index 1435707..06ab955 100644
--- a/storaged/include/storaged_utils.h
+++ b/storaged/include/storaged_utils.h
@@ -27,9 +27,8 @@
// Diskstats
bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats);
struct disk_perf get_disk_perf(struct disk_stats* stats);
-struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr);
+void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr, struct disk_stats* inc);
void add_disk_stats(struct disk_stats* src, struct disk_stats* dst);
-bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info);
// UID I/O
void sort_running_uids_info(std::vector<struct uid_info> &uids);
@@ -37,8 +36,4 @@
// Logging
void log_console_running_uids_info(const std::vector<struct uid_info>& uids, bool flag_dump_task);
-void log_debug_disk_perf(struct disk_perf* perf, const char* type);
-
-void log_event_disk_stats(struct disk_stats* stats, const char* type);
-void log_event_emmc_info(struct emmc_info* info_);
#endif /* _STORAGED_UTILS_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 49bd916..efab692 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -60,7 +60,7 @@
return NULL;
}
-static void help_message(void) {
+void help_message(void) {
printf("usage: storaged [OPTION]\n");
printf(" -u --uid Dump uid I/O usage to stdout\n");
printf(" -t --task Dump task I/O usage to stdout\n");
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 49592eb..0cf80a4 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -31,124 +31,8 @@
#include <storaged.h>
#include <storaged_utils.h>
-/* disk_stats_publisher */
-void disk_stats_publisher::publish(void) {
- // Logging
- struct disk_perf perf = get_disk_perf(&mAccumulate);
- log_debug_disk_perf(&perf, "regular");
- log_event_disk_stats(&mAccumulate, "regular");
- // Reset global structures
- memset(&mAccumulate, 0, sizeof(struct disk_stats));
-}
-void disk_stats_publisher::update(void) {
- struct disk_stats curr;
- if (parse_disk_stats(DISK_STATS_PATH, &curr)) {
- struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr);
- add_disk_stats(&inc, &mAccumulate);
-#ifdef DEBUG
-// log_kernel_disk_stats(&mPrevious, "prev stats");
-// log_kernel_disk_stats(&curr, "curr stats");
-// log_kernel_disk_stats(&inc, "inc stats");
-// log_kernel_disk_stats(&mAccumulate, "accumulated stats");
-#endif
- mPrevious = curr;
- }
-}
-
-/* disk_stats_monitor */
-void disk_stats_monitor::update_mean() {
- CHECK(mValid);
- mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
- mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
- mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
- mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
- mMean.queue = (uint32_t)mStats.queue.get_mean();
-}
-
-void disk_stats_monitor::update_std() {
- CHECK(mValid);
- mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
- mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
- mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
- mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
- mStd.queue = (uint32_t)mStats.queue.get_std();
-}
-
-void disk_stats_monitor::add(struct disk_perf* perf) {
- mStats.read_perf.add(perf->read_perf);
- mStats.read_ios.add(perf->read_ios);
- mStats.write_perf.add(perf->write_perf);
- mStats.write_ios.add(perf->write_ios);
- mStats.queue.add(perf->queue);
-}
-
-void disk_stats_monitor::evict(struct disk_perf* perf) {
- mStats.read_perf.evict(perf->read_perf);
- mStats.read_ios.evict(perf->read_ios);
- mStats.write_perf.evict(perf->write_perf);
- mStats.write_ios.evict(perf->write_ios);
- mStats.queue.evict(perf->queue);
-}
-
-bool disk_stats_monitor::detect(struct disk_perf* perf) {
- return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
- ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
- ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
-}
-
-void disk_stats_monitor::update(struct disk_stats* stats) {
- struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats);
- struct disk_perf perf = get_disk_perf(&inc);
- // Update internal data structures
- if (LIKELY(mValid)) {
- CHECK_EQ(mBuffer.size(), mWindow);
-
- if (UNLIKELY(detect(&perf))) {
- mStall = true;
- add_disk_stats(&inc, &mAccumulate);
- log_debug_disk_perf(&mMean, "stalled_mean");
- log_debug_disk_perf(&mStd, "stalled_std");
- } else {
- if (mStall) {
- struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
- log_debug_disk_perf(&acc_perf, "stalled");
- log_event_disk_stats(&mAccumulate, "stalled");
- mStall = false;
- memset(&mAccumulate, 0, sizeof(mAccumulate));
- }
- }
-
- evict(&mBuffer.front());
- mBuffer.pop();
- add(&perf);
- mBuffer.push(perf);
-
- update_mean();
- update_std();
-
- } else { /* mValid == false */
- CHECK_LT(mBuffer.size(), mWindow);
- add(&perf);
- mBuffer.push(perf);
- if (mBuffer.size() == mWindow) {
- mValid = true;
- update_mean();
- update_std();
- }
- }
-
- mPrevious = *stats;
-}
-
-void disk_stats_monitor::update(void) {
- struct disk_stats curr;
- if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) {
- update(&curr);
- }
-}
-
-static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
+sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) return NULL;
@@ -161,7 +45,7 @@
return battery_properties;
}
-static inline charger_stat_t is_charger_on(int64_t prop) {
+inline charger_stat_t is_charger_on(int64_t prop) {
return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
CHARGER_ON : CHARGER_OFF;
}
@@ -171,7 +55,7 @@
}
void storaged_t::init_battery_service() {
- if (!mConfig.proc_uid_io_available)
+ if (!mUidm.enabled())
return;
battery_properties = get_battery_properties_service();
@@ -206,43 +90,39 @@
/* storaged_t */
storaged_t::storaged_t(void) {
- if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
- mConfig.diskstats_available = false;
- } else {
- mConfig.diskstats_available = true;
- }
-
- mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0);
-
mConfig.periodic_chores_interval_unit =
- property_get_int32("ro.storaged.event.interval", DEFAULT_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);
+ property_get_int32("ro.storaged.disk_stats_pub",
+ DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
mConfig.periodic_chores_interval_uid_io =
- property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
+ property_get_int32("ro.storaged.uid_io.interval",
+ DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
storage_info.reset(storage_info_t::get_storage_info());
mStarttime = time(NULL);
+ mTimer = 0;
}
void storaged_t::event(void) {
- if (mConfig.diskstats_available) {
- mDiskStats.update();
+ storage_info->refresh();
+
+ if (mDsm.enabled()) {
mDsm.update();
- storage_info->refresh();
- if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
- mDiskStats.publish();
+ if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) {
+ mDsm.publish();
}
}
- if (mConfig.proc_uid_io_available && mTimer &&
- (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
+ if (mUidm.enabled() &&
+ !(mTimer % mConfig.periodic_chores_interval_uid_io)) {
mUidm.report();
}
diff --git a/storaged/storaged_diskstats.cpp b/storaged/storaged_diskstats.cpp
new file mode 100644
index 0000000..0604e0a
--- /dev/null
+++ b/storaged/storaged_diskstats.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <sstream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <log/log_event_list.h>
+
+#include "storaged.h"
+#include "storaged_diskstats.h"
+
+namespace {
+
+#ifdef DEBUG
+void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
+ // skip if the input structure are all zeros
+ if (perf == NULL || perf->is_zero()) return;
+
+ LOG_TO(SYSTEM, INFO) << "disk_perf " << type
+ << " rd: " << perf->read_perf << " kbps, " << perf->read_ios << " iops"
+ << " wr: " << perf->write_perf << " kbps, " << perf->write_ios << " iops"
+ << " q: " << perf->queue;
+}
+#else
+void log_debug_disk_perf(struct disk_perf* perf, const char* type) {}
+#endif
+
+void log_event_disk_stats(struct disk_stats* stats, const char* type) {
+ // skip if the input structure are all zeros
+ if (stats == NULL || stats->is_zero()) return;
+
+ android_log_event_list(EVENTLOGTAG_DISKSTATS)
+ << type << stats->start_time << stats->end_time
+ << stats->read_ios << stats->read_merges
+ << stats->read_sectors << stats->read_ticks
+ << stats->write_ios << stats->write_merges
+ << stats->write_sectors << stats->write_ticks
+ << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
+ << LOG_ID_EVENTS;
+}
+
+} // namespace
+
+bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats)
+{
+ // Get time
+ struct timespec ts;
+ // Use monotonic to exclude suspend time so that we measure IO bytes/sec
+ // when system is running.
+ int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret < 0) {
+ PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+ return false;
+ }
+
+ std::string buffer;
+ if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
+ PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
+ return false;
+ }
+
+ // Regular diskstats entries
+ std::stringstream ss(buffer);
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ ss >> *((uint64_t*)stats + i);
+ }
+ // Other entries
+ stats->start_time = 0;
+ stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
+ ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
+ stats->counter = 1;
+ stats->io_avg = (double)stats->io_in_flight;
+ return true;
+}
+
+struct disk_perf get_disk_perf(struct disk_stats* stats)
+{
+ struct disk_perf perf = {};
+
+ if (stats->io_ticks) {
+ if (stats->read_ticks) {
+ unsigned long long divisor = stats->read_ticks * stats->io_ticks;
+ perf.read_perf = ((unsigned long long)SECTOR_SIZE *
+ stats->read_sectors * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
+ stats->read_ios * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ }
+ if (stats->write_ticks) {
+ unsigned long long divisor = stats->write_ticks * stats->io_ticks;
+ perf.write_perf = ((unsigned long long)SECTOR_SIZE *
+ stats->write_sectors * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
+ stats->write_ios * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ }
+ perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
+ stats->io_ticks;
+ }
+ return perf;
+}
+
+void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr,
+ struct disk_stats* inc)
+{
+ *inc = *curr - *prev;
+ inc->start_time = prev->end_time;
+ inc->end_time = curr->end_time;
+ inc->io_avg = curr->io_avg;
+ inc->counter = 1;
+}
+
+// Add src to dst
+void add_disk_stats(struct disk_stats* src, struct disk_stats* dst)
+{
+ if (dst->end_time != 0 && dst->end_time != src->start_time) {
+ LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
+ << " are added. dst end with " << dst->end_time
+ << ", src start with " << src->start_time;
+ }
+
+ *dst += *src;
+
+ dst->io_in_flight = src->io_in_flight;
+ if (dst->counter + src->counter) {
+ dst->io_avg =
+ ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
+ (dst->counter + src->counter);
+ }
+ dst->counter += src->counter;
+ dst->end_time = src->end_time;
+ if (dst->start_time == 0) {
+ dst->start_time = src->start_time;
+ }
+}
+
+/* disk_stats_monitor */
+void disk_stats_monitor::update_mean()
+{
+ CHECK(mValid);
+ mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
+ mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
+ mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
+ mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
+ mMean.queue = (uint32_t)mStats.queue.get_mean();
+}
+
+void disk_stats_monitor::update_std()
+{
+ CHECK(mValid);
+ mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
+ mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
+ mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
+ mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
+ mStd.queue = (uint32_t)mStats.queue.get_std();
+}
+
+void disk_stats_monitor::add(struct disk_perf* perf)
+{
+ mStats.read_perf.add(perf->read_perf);
+ mStats.read_ios.add(perf->read_ios);
+ mStats.write_perf.add(perf->write_perf);
+ mStats.write_ios.add(perf->write_ios);
+ mStats.queue.add(perf->queue);
+}
+
+void disk_stats_monitor::evict(struct disk_perf* perf) {
+ mStats.read_perf.evict(perf->read_perf);
+ mStats.read_ios.evict(perf->read_ios);
+ mStats.write_perf.evict(perf->write_perf);
+ mStats.write_ios.evict(perf->write_ios);
+ mStats.queue.evict(perf->queue);
+}
+
+bool disk_stats_monitor::detect(struct disk_perf* perf)
+{
+ return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
+ ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
+ ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
+}
+
+void disk_stats_monitor::update(struct disk_stats* curr)
+{
+ disk_stats inc;
+ get_inc_disk_stats(&mPrevious, curr, &inc);
+ add_disk_stats(&inc, &mAccumulate_pub);
+
+ struct disk_perf perf = get_disk_perf(&inc);
+ log_debug_disk_perf(&perf, "regular");
+
+ add(&perf);
+ mBuffer.push(perf);
+ if (mBuffer.size() > mWindow) {
+ evict(&mBuffer.front());
+ mBuffer.pop();
+ mValid = true;
+ }
+
+ // Update internal data structures
+ if (LIKELY(mValid)) {
+ CHECK_EQ(mBuffer.size(), mWindow);
+ update_mean();
+ update_std();
+ if (UNLIKELY(detect(&perf))) {
+ mStall = true;
+ add_disk_stats(&inc, &mAccumulate);
+ log_debug_disk_perf(&mMean, "stalled_mean");
+ log_debug_disk_perf(&mStd, "stalled_std");
+ } else {
+ if (mStall) {
+ struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
+ log_debug_disk_perf(&acc_perf, "stalled");
+ log_event_disk_stats(&mAccumulate, "stalled");
+ mStall = false;
+ memset(&mAccumulate, 0, sizeof(mAccumulate));
+ }
+ }
+ }
+
+ mPrevious = *curr;
+}
+
+void disk_stats_monitor::update() {
+ disk_stats curr;
+ if (!parse_disk_stats(DISK_STATS_PATH, &curr)) {
+ return;
+ }
+
+ update(&curr);
+}
+
+void disk_stats_monitor::publish(void)
+{
+ struct disk_perf perf = get_disk_perf(&mAccumulate_pub);
+ log_debug_disk_perf(&perf, "regular");
+ log_event_disk_stats(&mAccumulate, "regular");
+ // Reset global structures
+ memset(&mAccumulate_pub, 0, sizeof(struct disk_stats));
+}
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index b5fb13e..fc2351f 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -39,12 +39,16 @@
const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
-static bool FileExists(const std::string& filename)
+namespace {
+
+bool FileExists(const std::string& filename)
{
struct stat buffer;
return stat(filename.c_str(), &buffer) == 0;
}
+} // namespace
+
storage_info_t* storage_info_t::get_storage_info()
{
if (FileExists(emmc_info_t::emmc_sysfs) ||
@@ -121,6 +125,8 @@
return true;
}
+namespace {
+
const size_t EXT_CSD_FILE_MIN_SIZE = 1024;
/* 2 characters in string for each byte */
const size_t EXT_CSD_REV_IDX = 192 * 2;
@@ -128,6 +134,8 @@
const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2;
const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2;
+} // namespace
+
bool emmc_info_t::report_debugfs()
{
string buffer;
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index a69bc33..66a9e35 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -45,11 +45,16 @@
using namespace google::protobuf::io;
using namespace storaged_proto;
-static bool refresh_uid_names;
-static const uint32_t crc_init = 0x5108A4ED; /* STORAGED */
+namespace {
+
+bool refresh_uid_names;
+const uint32_t crc_init = 0x5108A4ED; /* STORAGED */
+const char* UID_IO_STATS_PATH = "/proc/uid_io/stats";
+
+} // namepsace
const std::string uid_monitor::io_history_proto_file =
- "/data/misc/storaged/io_history.proto";
+"/data/misc/storaged/io_history.proto";
std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
{
@@ -119,7 +124,9 @@
return true;
}
-static void get_uid_names(const vector<int>& uids, const vector<std::string*>& uid_names)
+namespace {
+
+void get_uid_names(const vector<int>& uids, const vector<std::string*>& uid_names)
{
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) {
@@ -151,6 +158,8 @@
refresh_uid_names = false;
}
+} // namespace
+
std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
{
std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
@@ -197,9 +206,11 @@
return uid_io_stats;
}
-static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
+namespace {
-static inline size_t history_size(
+const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
+
+inline size_t history_size(
const std::map<uint64_t, struct uid_records>& history)
{
size_t count = 0;
@@ -209,6 +220,8 @@
return count;
}
+} // namespace
+
void uid_monitor::add_records_locked(uint64_t curr_ts)
{
// remove records more than 5 days old
@@ -367,7 +380,9 @@
flush_io_history_to_proto();
}
-static void set_io_usage_proto(IOUsage* usage_proto, const struct io_usage& usage)
+namespace {
+
+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]);
@@ -379,7 +394,7 @@
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)
+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();
@@ -391,6 +406,8 @@
usage->bytes[WRITE][BACKGROUND][CHARGER_OFF] = io_proto.wr_bg_chg_off();
}
+} // namespace
+
void uid_monitor::flush_io_history_to_proto()
{
UidIOHistoryProto out_proto;
@@ -510,6 +527,7 @@
}
uid_monitor::uid_monitor()
+ : enable(!access(UID_IO_STATS_PATH, R_OK))
{
sem_init(&um_lock, 0, 1);
}
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
index 59cf251..533bf78 100644
--- a/storaged/storaged_utils.cpp
+++ b/storaged/storaged_utils.cpp
@@ -42,124 +42,7 @@
#include <storaged.h>
#include <storaged_utils.h>
-bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
- // Get time
- struct timespec ts;
- // Use monotonic to exclude suspend time so that we measure IO bytes/sec
- // when system is running.
- int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
- return false;
- }
-
- std::string buffer;
- if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
- PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
- return false;
- }
-
- // Regular diskstats entries
- std::stringstream ss(buffer);
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- ss >> *((uint64_t*)stats + i);
- }
- // Other entries
- stats->start_time = 0;
- stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
- ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
- stats->counter = 1;
- stats->io_avg = (double)stats->io_in_flight;
- return true;
-}
-
-struct disk_perf get_disk_perf(struct disk_stats* stats) {
- struct disk_perf perf;
- memset(&perf, 0, sizeof(struct disk_perf)); // initialize
-
- if (stats->io_ticks) {
- if (stats->read_ticks) {
- unsigned long long divisor = stats->read_ticks * stats->io_ticks;
- perf.read_perf = ((unsigned long long)SECTOR_SIZE *
- stats->read_sectors *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
- stats->read_ios *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- }
- if (stats->write_ticks) {
- unsigned long long divisor = stats->write_ticks * stats->io_ticks;
- perf.write_perf = ((unsigned long long)SECTOR_SIZE *
- stats->write_sectors *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
- stats->write_ios *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- }
- perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
- stats->io_ticks;
- }
- return perf;
-}
-
-struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
- struct disk_stats inc;
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
- continue;
- }
-
- *((uint64_t*)&inc + i) =
- *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
- }
- // io_in_flight is exception
- inc.io_in_flight = curr->io_in_flight;
-
- inc.start_time = prev->end_time;
- inc.end_time = curr->end_time;
- inc.io_avg = curr->io_avg;
- inc.counter = 1;
-
- return inc;
-}
-
-// Add src to dst
-void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
- if (dst->end_time != 0 && dst->end_time != src->start_time) {
- LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
- << " are added. dst end with " << dst->end_time
- << ", src start with " << src->start_time;
- }
-
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
- continue;
- }
-
- *((uint64_t*)dst + i) += *((uint64_t*)src + i);
- }
-
- dst->io_in_flight = src->io_in_flight;
- if (dst->counter + src->counter) {
- dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
- (dst->counter + src->counter);
- }
- dst->counter += src->counter;
- dst->end_time = src->end_time;
- if (dst->start_time == 0) {
- dst->start_time = src->start_time;
- }
-}
-
-static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
+bool cmp_uid_info(struct uid_info l, struct uid_info r) {
// Compare background I/O first.
for (int i = UID_STATS - 1; i >= 0; i--) {
uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
@@ -208,39 +91,3 @@
}
fflush(stdout);
}
-
-#if DEBUG
-void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
- // skip if the input structure are all zeros
- if (perf == NULL) return;
- struct disk_perf zero_cmp;
- memset(&zero_cmp, 0, sizeof(zero_cmp));
- if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
-
- LOG_TO(SYSTEM, INFO) << "perf(ios) " << type
- << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)"
- << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)"
- << " q:" << perf->queue;
-}
-#else
-void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {}
-#endif
-
-void log_event_disk_stats(struct disk_stats* stats, const char* type) {
- // skip if the input structure are all zeros
- if (stats == NULL) return;
- struct disk_stats zero_cmp;
- memset(&zero_cmp, 0, sizeof(zero_cmp));
- // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
- if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
-
- android_log_event_list(EVENTLOGTAG_DISKSTATS)
- << type << stats->start_time << stats->end_time
- << stats->read_ios << stats->read_merges
- << stats->read_sectors << stats->read_ticks
- << stats->write_ios << stats->write_merges
- << stats->write_sectors << stats->write_ticks
- << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
- << LOG_ID_EVENTS;
-}
-
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index b103ac1..bd14d76 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -30,7 +30,9 @@
#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
-static void pause(uint32_t sec) {
+namespace {
+
+void write_and_pause(uint32_t sec) {
const char* path = "/cache/test";
int fd = open(path, O_WRONLY | O_CREAT, 0600);
ASSERT_LT(-1, fd);
@@ -53,6 +55,8 @@
sleep(sec);
}
+} // namespace
+
// the return values of the tested functions should be the expected ones
const char* DISK_STATS_PATH;
TEST(storaged_test, retvals) {
@@ -77,13 +81,11 @@
EXPECT_FALSE(parse_disk_stats(wrong_path, &stats));
// reading a wrong path should not damage the output structure
- EXPECT_EQ(0, memcmp(&stats, &old_stats, sizeof(disk_stats)));
+ EXPECT_EQ(stats, old_stats);
}
TEST(storaged_test, disk_stats) {
- struct disk_stats stats;
- memset(&stats, 0, sizeof(struct disk_stats));
-
+ struct disk_stats stats = {};
ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
// every entry of stats (except io_in_flight) should all be greater than 0
@@ -93,11 +95,7 @@
}
// accumulation of the increments should be the same with the overall increment
- struct disk_stats base, tmp, curr, acc, inc[5];
- memset(&base, 0, sizeof(struct disk_stats));
- memset(&tmp, 0, sizeof(struct disk_stats));
- memset(&acc, 0, sizeof(struct disk_stats));
-
+ struct disk_stats base = {}, tmp = {}, curr, acc = {}, inc[5];
for (uint i = 0; i < 5; ++i) {
ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &curr));
if (i == 0) {
@@ -106,22 +104,18 @@
sleep(5);
continue;
}
- inc[i] = get_inc_disk_stats(&tmp, &curr);
+ get_inc_disk_stats(&tmp, &curr, &inc[i]);
add_disk_stats(&inc[i], &acc);
tmp = curr;
- pause(5);
+ write_and_pause(5);
}
- struct disk_stats overall_inc;
- memset(&overall_inc, 0, sizeof(disk_stats));
- overall_inc= get_inc_disk_stats(&base, &curr);
+ struct disk_stats overall_inc = {};
+ get_inc_disk_stats(&base, &curr, &overall_inc);
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- if (i == 8) continue; // skip io_in_flight which can be 0
- EXPECT_EQ(*((uint64_t*)&overall_inc + i), *((uint64_t*)&acc + i));
- }
+ EXPECT_EQ(overall_inc, acc);
}
-static double mean(std::deque<uint32_t> nums) {
+double mean(std::deque<uint32_t> nums) {
double sum = 0.0;
for (uint32_t i : nums) {
sum += i;
@@ -129,7 +123,7 @@
return sum / nums.size();
}
-static double standard_deviation(std::deque<uint32_t> nums) {
+double standard_deviation(std::deque<uint32_t> nums) {
double sum = 0.0;
double avg = mean(nums);
for (uint32_t i : nums) {
@@ -181,7 +175,7 @@
}
}
-static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) {
+struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) {
struct disk_perf retval;
retval.read_perf = (double)perf.read_perf * mul;
retval.read_ios = (double)perf.read_ios * mul;
@@ -192,7 +186,7 @@
return retval;
}
-static struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) {
+struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) {
struct disk_stats retval;
retval.read_ios = stats1.read_ios + stats2.read_ios;
retval.read_merges = stats1.read_merges + stats2.read_merges;
@@ -210,6 +204,30 @@
return retval;
}
+void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
+ EXPECT_LE(stats1.read_ios, stats2.read_ios);
+ EXPECT_LE(stats1.read_merges, stats2.read_merges);
+ EXPECT_LE(stats1.read_sectors, stats2.read_sectors);
+ EXPECT_LE(stats1.read_ticks, stats2.read_ticks);
+ EXPECT_LE(stats1.write_ios, stats2.write_ios);
+ EXPECT_LE(stats1.write_merges, stats2.write_merges);
+ EXPECT_LE(stats1.write_sectors, stats2.write_sectors);
+ EXPECT_LE(stats1.write_ticks, stats2.write_ticks);
+ EXPECT_LE(stats1.io_ticks, stats2.io_ticks);
+ EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue);
+
+ EXPECT_TRUE(stats1.read_ios < stats2.read_ios ||
+ stats1.read_merges < stats2.read_merges ||
+ stats1.read_sectors < stats2.read_sectors ||
+ stats1.read_ticks < stats2.read_ticks ||
+ stats1.write_ios < stats2.write_ios ||
+ stats1.write_merges < stats2.write_merges ||
+ stats1.write_sectors < stats2.write_sectors ||
+ stats1.write_ticks < stats2.write_ticks ||
+ stats1.io_ticks < stats2.io_ticks ||
+ stats1.io_in_queue < stats2.io_in_queue);
+}
+
TEST(storaged_test, disk_stats_monitor) {
// 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);
@@ -294,14 +312,12 @@
.io_avg = 0
};
- struct disk_stats stats_base;
- memset(&stats_base, 0, sizeof(stats_base));
-
+ struct disk_stats stats_base = {};
int loop_size = 100;
for (int i = 0; i < loop_size; ++i) {
stats_base = disk_stats_add(stats_base, norm_inc);
dsm_acc.update(&stats_base);
- EXPECT_EQ(dsm_acc.mValid, (uint32_t)(i + 1) >= dsm_acc.mWindow);
+ EXPECT_EQ(dsm_acc.mValid, (uint32_t)i >= dsm_acc.mWindow);
EXPECT_FALSE(dsm_acc.mStall);
}
@@ -316,36 +332,14 @@
EXPECT_TRUE(dsm_acc.mValid);
EXPECT_FALSE(dsm_acc.mStall);
}
-}
-static void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
- EXPECT_LE(stats1.read_ios, stats2.read_ios);
- EXPECT_LE(stats1.read_merges, stats2.read_merges);
- EXPECT_LE(stats1.read_sectors, stats2.read_sectors);
- EXPECT_LE(stats1.read_ticks, stats2.read_ticks);
-
- EXPECT_LE(stats1.write_ios, stats2.write_ios);
- EXPECT_LE(stats1.write_merges, stats2.write_merges);
- EXPECT_LE(stats1.write_sectors, stats2.write_sectors);
- EXPECT_LE(stats1.write_ticks, stats2.write_ticks);
-
- EXPECT_LE(stats1.io_ticks, stats2.io_ticks);
- 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);
- disk_stats_publisher dsp;
- struct disk_stats prev;
- memset(&prev, 0, sizeof(prev));
-
- for (int i = 0; i < TEST_LOOPS; ++i) {
- dsp.update();
- expect_increasing(prev, dsp.mPrevious);
- prev = dsp.mPrevious;
- pause(10);
+ struct disk_stats stats_prev = {};
+ loop_size = 10;
+ write_and_pause(5);
+ for (int i = 0; i < loop_size; ++i) {
+ dsm_detect.update();
+ expect_increasing(stats_prev, dsm_detect.mPrevious);
+ stats_prev = dsm_detect.mPrevious;
+ write_and_pause(5);
}
}
-