123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- /*
- * 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 {
- using android::sp;
- using android::hardware::health::V2_0::DiskStats;
- using android::hardware::health::V2_0::IHealth;
- using android::hardware::health::V2_0::Result;
- using android::hardware::health::V2_0::toString;
- #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 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;
- }
- return true;
- }
- void init_disk_stats_other(const struct timespec& ts, struct disk_stats* stats) {
- 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;
- }
- bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
- // Get time
- struct timespec ts;
- if (!get_time(&ts)) {
- 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
- init_disk_stats_other(ts, stats);
- return true;
- }
- void convert_hal_disk_stats(struct disk_stats* dst, const DiskStats& src) {
- dst->read_ios = src.reads;
- dst->read_merges = src.readMerges;
- dst->read_sectors = src.readSectors;
- dst->read_ticks = src.readTicks;
- dst->write_ios = src.writes;
- dst->write_merges = src.writeMerges;
- dst->write_sectors = src.writeSectors;
- dst->write_ticks = src.writeTicks;
- dst->io_in_flight = src.ioInFlight;
- dst->io_ticks = src.ioTicks;
- dst->io_in_queue = src.ioInQueue;
- }
- bool get_disk_stats_from_health_hal(const sp<IHealth>& service, struct disk_stats* stats) {
- struct timespec ts;
- if (!get_time(&ts)) {
- return false;
- }
- bool success = false;
- auto ret = service->getDiskStats([&success, stats](auto result, const auto& halStats) {
- if (result == Result::NOT_SUPPORTED) {
- LOG_TO(SYSTEM, DEBUG) << "getDiskStats is not supported on health HAL.";
- return;
- }
- if (result != Result::SUCCESS || halStats.size() == 0) {
- LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with result " << toString(result)
- << " and size " << halStats.size();
- return;
- }
- convert_hal_disk_stats(stats, halStats[0]);
- success = true;
- });
- if (!ret.isOk()) {
- LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with " << ret.description();
- return false;
- }
- if (!success) {
- return false;
- }
- init_disk_stats_other(ts, stats);
- 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 (mHealth != nullptr) {
- if (!get_disk_stats_from_health_hal(mHealth, &curr)) {
- return;
- }
- } else {
- 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));
- }
|