storaged_diskstats.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Copyright (C) 2017 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define LOG_TAG "storaged"
  17. #include <stdint.h>
  18. #include <stdlib.h>
  19. #include <sstream>
  20. #include <android-base/file.h>
  21. #include <android-base/logging.h>
  22. #include <log/log_event_list.h>
  23. #include "storaged.h"
  24. #include "storaged_diskstats.h"
  25. namespace {
  26. using android::sp;
  27. using android::hardware::health::V2_0::DiskStats;
  28. using android::hardware::health::V2_0::IHealth;
  29. using android::hardware::health::V2_0::Result;
  30. using android::hardware::health::V2_0::toString;
  31. #ifdef DEBUG
  32. void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
  33. // skip if the input structure are all zeros
  34. if (perf == NULL || perf->is_zero()) return;
  35. LOG_TO(SYSTEM, INFO) << "disk_perf " << type
  36. << " rd: " << perf->read_perf << " kbps, " << perf->read_ios << " iops"
  37. << " wr: " << perf->write_perf << " kbps, " << perf->write_ios << " iops"
  38. << " q: " << perf->queue;
  39. }
  40. #else
  41. void log_debug_disk_perf(struct disk_perf* perf, const char* type) {}
  42. #endif
  43. void log_event_disk_stats(struct disk_stats* stats, const char* type) {
  44. // skip if the input structure are all zeros
  45. if (stats == NULL || stats->is_zero()) return;
  46. android_log_event_list(EVENTLOGTAG_DISKSTATS)
  47. << type << stats->start_time << stats->end_time
  48. << stats->read_ios << stats->read_merges
  49. << stats->read_sectors << stats->read_ticks
  50. << stats->write_ios << stats->write_merges
  51. << stats->write_sectors << stats->write_ticks
  52. << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
  53. << LOG_ID_EVENTS;
  54. }
  55. } // namespace
  56. bool get_time(struct timespec* ts) {
  57. // Use monotonic to exclude suspend time so that we measure IO bytes/sec
  58. // when system is running.
  59. int ret = clock_gettime(CLOCK_MONOTONIC, ts);
  60. if (ret < 0) {
  61. PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
  62. return false;
  63. }
  64. return true;
  65. }
  66. void init_disk_stats_other(const struct timespec& ts, struct disk_stats* stats) {
  67. stats->start_time = 0;
  68. stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC + ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
  69. stats->counter = 1;
  70. stats->io_avg = (double)stats->io_in_flight;
  71. }
  72. bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
  73. // Get time
  74. struct timespec ts;
  75. if (!get_time(&ts)) {
  76. return false;
  77. }
  78. std::string buffer;
  79. if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
  80. PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
  81. return false;
  82. }
  83. // Regular diskstats entries
  84. std::stringstream ss(buffer);
  85. for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
  86. ss >> *((uint64_t*)stats + i);
  87. }
  88. // Other entries
  89. init_disk_stats_other(ts, stats);
  90. return true;
  91. }
  92. void convert_hal_disk_stats(struct disk_stats* dst, const DiskStats& src) {
  93. dst->read_ios = src.reads;
  94. dst->read_merges = src.readMerges;
  95. dst->read_sectors = src.readSectors;
  96. dst->read_ticks = src.readTicks;
  97. dst->write_ios = src.writes;
  98. dst->write_merges = src.writeMerges;
  99. dst->write_sectors = src.writeSectors;
  100. dst->write_ticks = src.writeTicks;
  101. dst->io_in_flight = src.ioInFlight;
  102. dst->io_ticks = src.ioTicks;
  103. dst->io_in_queue = src.ioInQueue;
  104. }
  105. bool get_disk_stats_from_health_hal(const sp<IHealth>& service, struct disk_stats* stats) {
  106. struct timespec ts;
  107. if (!get_time(&ts)) {
  108. return false;
  109. }
  110. bool success = false;
  111. auto ret = service->getDiskStats([&success, stats](auto result, const auto& halStats) {
  112. if (result == Result::NOT_SUPPORTED) {
  113. LOG_TO(SYSTEM, DEBUG) << "getDiskStats is not supported on health HAL.";
  114. return;
  115. }
  116. if (result != Result::SUCCESS || halStats.size() == 0) {
  117. LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with result " << toString(result)
  118. << " and size " << halStats.size();
  119. return;
  120. }
  121. convert_hal_disk_stats(stats, halStats[0]);
  122. success = true;
  123. });
  124. if (!ret.isOk()) {
  125. LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with " << ret.description();
  126. return false;
  127. }
  128. if (!success) {
  129. return false;
  130. }
  131. init_disk_stats_other(ts, stats);
  132. return true;
  133. }
  134. struct disk_perf get_disk_perf(struct disk_stats* stats)
  135. {
  136. struct disk_perf perf = {};
  137. if (stats->io_ticks) {
  138. if (stats->read_ticks) {
  139. unsigned long long divisor = stats->read_ticks * stats->io_ticks;
  140. perf.read_perf = ((unsigned long long)SECTOR_SIZE *
  141. stats->read_sectors * stats->io_in_queue +
  142. (divisor >> 1)) / divisor;
  143. perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
  144. stats->read_ios * stats->io_in_queue +
  145. (divisor >> 1)) / divisor;
  146. }
  147. if (stats->write_ticks) {
  148. unsigned long long divisor = stats->write_ticks * stats->io_ticks;
  149. perf.write_perf = ((unsigned long long)SECTOR_SIZE *
  150. stats->write_sectors * stats->io_in_queue +
  151. (divisor >> 1)) / divisor;
  152. perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
  153. stats->write_ios * stats->io_in_queue +
  154. (divisor >> 1)) / divisor;
  155. }
  156. perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
  157. stats->io_ticks;
  158. }
  159. return perf;
  160. }
  161. void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr,
  162. struct disk_stats* inc)
  163. {
  164. *inc = *curr - *prev;
  165. inc->start_time = prev->end_time;
  166. inc->end_time = curr->end_time;
  167. inc->io_avg = curr->io_avg;
  168. inc->counter = 1;
  169. }
  170. // Add src to dst
  171. void add_disk_stats(struct disk_stats* src, struct disk_stats* dst)
  172. {
  173. if (dst->end_time != 0 && dst->end_time != src->start_time) {
  174. LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
  175. << " are added. dst end with " << dst->end_time
  176. << ", src start with " << src->start_time;
  177. }
  178. *dst += *src;
  179. dst->io_in_flight = src->io_in_flight;
  180. if (dst->counter + src->counter) {
  181. dst->io_avg =
  182. ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
  183. (dst->counter + src->counter);
  184. }
  185. dst->counter += src->counter;
  186. dst->end_time = src->end_time;
  187. if (dst->start_time == 0) {
  188. dst->start_time = src->start_time;
  189. }
  190. }
  191. /* disk_stats_monitor */
  192. void disk_stats_monitor::update_mean()
  193. {
  194. CHECK(mValid);
  195. mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
  196. mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
  197. mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
  198. mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
  199. mMean.queue = (uint32_t)mStats.queue.get_mean();
  200. }
  201. void disk_stats_monitor::update_std()
  202. {
  203. CHECK(mValid);
  204. mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
  205. mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
  206. mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
  207. mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
  208. mStd.queue = (uint32_t)mStats.queue.get_std();
  209. }
  210. void disk_stats_monitor::add(struct disk_perf* perf)
  211. {
  212. mStats.read_perf.add(perf->read_perf);
  213. mStats.read_ios.add(perf->read_ios);
  214. mStats.write_perf.add(perf->write_perf);
  215. mStats.write_ios.add(perf->write_ios);
  216. mStats.queue.add(perf->queue);
  217. }
  218. void disk_stats_monitor::evict(struct disk_perf* perf) {
  219. mStats.read_perf.evict(perf->read_perf);
  220. mStats.read_ios.evict(perf->read_ios);
  221. mStats.write_perf.evict(perf->write_perf);
  222. mStats.write_ios.evict(perf->write_ios);
  223. mStats.queue.evict(perf->queue);
  224. }
  225. bool disk_stats_monitor::detect(struct disk_perf* perf)
  226. {
  227. return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
  228. ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
  229. ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
  230. }
  231. void disk_stats_monitor::update(struct disk_stats* curr)
  232. {
  233. disk_stats inc;
  234. get_inc_disk_stats(&mPrevious, curr, &inc);
  235. add_disk_stats(&inc, &mAccumulate_pub);
  236. struct disk_perf perf = get_disk_perf(&inc);
  237. log_debug_disk_perf(&perf, "regular");
  238. add(&perf);
  239. mBuffer.push(perf);
  240. if (mBuffer.size() > mWindow) {
  241. evict(&mBuffer.front());
  242. mBuffer.pop();
  243. mValid = true;
  244. }
  245. // Update internal data structures
  246. if (LIKELY(mValid)) {
  247. CHECK_EQ(mBuffer.size(), mWindow);
  248. update_mean();
  249. update_std();
  250. if (UNLIKELY(detect(&perf))) {
  251. mStall = true;
  252. add_disk_stats(&inc, &mAccumulate);
  253. log_debug_disk_perf(&mMean, "stalled_mean");
  254. log_debug_disk_perf(&mStd, "stalled_std");
  255. } else {
  256. if (mStall) {
  257. struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
  258. log_debug_disk_perf(&acc_perf, "stalled");
  259. log_event_disk_stats(&mAccumulate, "stalled");
  260. mStall = false;
  261. memset(&mAccumulate, 0, sizeof(mAccumulate));
  262. }
  263. }
  264. }
  265. mPrevious = *curr;
  266. }
  267. void disk_stats_monitor::update() {
  268. disk_stats curr;
  269. if (mHealth != nullptr) {
  270. if (!get_disk_stats_from_health_hal(mHealth, &curr)) {
  271. return;
  272. }
  273. } else {
  274. if (!parse_disk_stats(DISK_STATS_PATH, &curr)) {
  275. return;
  276. }
  277. }
  278. update(&curr);
  279. }
  280. void disk_stats_monitor::publish(void)
  281. {
  282. struct disk_perf perf = get_disk_perf(&mAccumulate_pub);
  283. log_debug_disk_perf(&perf, "regular");
  284. log_event_disk_stats(&mAccumulate, "regular");
  285. // Reset global structures
  286. memset(&mAccumulate_pub, 0, sizeof(struct disk_stats));
  287. }