blob: 9fcf1fa8af347d26d631c63b2253001495578db1 [file] [log] [blame]
ynwang62cb3722016-06-17 14:30:48 -07001/*
2 * Copyright (C) 2016 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
17#define LOG_TAG "storaged"
18
ynwang62cb3722016-06-17 14:30:48 -070019#include <dirent.h>
ynwangaf49d972016-06-17 14:30:48 -070020#include <fcntl.h>
21#include <linux/time.h>
ynwang62cb3722016-06-17 14:30:48 -070022#include <stdint.h>
ynwangaf49d972016-06-17 14:30:48 -070023#include <stdio.h>
ynwang62cb3722016-06-17 14:30:48 -070024#include <stdlib.h>
25#include <string.h>
ynwangaf49d972016-06-17 14:30:48 -070026#include <sys/stat.h>
27#include <time.h>
ynwang62cb3722016-06-17 14:30:48 -070028#include <unistd.h>
29
Jin Qian535ddbe2017-01-11 17:19:21 -080030#include <iomanip>
ynwang62cb3722016-06-17 14:30:48 -070031#include <sstream>
32#include <string>
33#include <unordered_map>
34
35#include <android-base/file.h>
ynwangaf49d972016-06-17 14:30:48 -070036#include <android-base/logging.h>
ynwang62cb3722016-06-17 14:30:48 -070037#include <android-base/stringprintf.h>
38#include <android-base/strings.h>
ynwang62cb3722016-06-17 14:30:48 -070039#include <log/log_event_list.h>
ynwang62cb3722016-06-17 14:30:48 -070040
41#include <storaged.h>
42#include <storaged_utils.h>
43
ynwang62cb3722016-06-17 14:30:48 -070044bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
45 // Get time
46 struct timespec ts;
47 // Use monotonic to exclude suspend time so that we measure IO bytes/sec
48 // when system is running.
49 int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
50 if (ret < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -080051 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
ynwang62cb3722016-06-17 14:30:48 -070052 return false;
53 }
54
55 std::string buffer;
56 if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
Jin Qian535ddbe2017-01-11 17:19:21 -080057 PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
ynwang62cb3722016-06-17 14:30:48 -070058 return false;
59 }
60
61 // Regular diskstats entries
62 std::stringstream ss(buffer);
63 for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
64 ss >> *((uint64_t*)stats + i);
65 }
66 // Other entries
67 stats->start_time = 0;
68 stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
69 ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
70 stats->counter = 1;
71 stats->io_avg = (double)stats->io_in_flight;
72 return true;
73}
74
75struct disk_perf get_disk_perf(struct disk_stats* stats) {
76 struct disk_perf perf;
77 memset(&perf, 0, sizeof(struct disk_perf)); // initialize
78
79 if (stats->io_ticks) {
80 if (stats->read_ticks) {
81 unsigned long long divisor = stats->read_ticks * stats->io_ticks;
82 perf.read_perf = ((unsigned long long)SECTOR_SIZE *
83 stats->read_sectors *
84 stats->io_in_queue +
85 (divisor >> 1)) /
86 divisor;
87 perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
88 stats->read_ios *
89 stats->io_in_queue +
90 (divisor >> 1)) /
91 divisor;
92 }
93 if (stats->write_ticks) {
94 unsigned long long divisor = stats->write_ticks * stats->io_ticks;
95 perf.write_perf = ((unsigned long long)SECTOR_SIZE *
96 stats->write_sectors *
97 stats->io_in_queue +
98 (divisor >> 1)) /
99 divisor;
100 perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
101 stats->write_ios *
102 stats->io_in_queue +
103 (divisor >> 1)) /
104 divisor;
105 }
106 perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
107 stats->io_ticks;
108 }
109 return perf;
110}
111
112struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
113 struct disk_stats inc;
114 for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
115 if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
116 continue;
117 }
118
119 *((uint64_t*)&inc + i) =
120 *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
121 }
122 // io_in_flight is exception
123 inc.io_in_flight = curr->io_in_flight;
124
125 inc.start_time = prev->end_time;
126 inc.end_time = curr->end_time;
127 inc.io_avg = curr->io_avg;
128 inc.counter = 1;
129
130 return inc;
131}
132
133// Add src to dst
134void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800135 if (dst->end_time != 0 && dst->end_time != src->start_time) {
136 LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
137 << " are added. dst end with " << dst->end_time
138 << ", src start with " << src->start_time;
ynwang62cb3722016-06-17 14:30:48 -0700139 }
140
141 for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
142 if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
143 continue;
144 }
145
146 *((uint64_t*)dst + i) += *((uint64_t*)src + i);
147 }
148
149 dst->io_in_flight = src->io_in_flight;
150 if (dst->counter + src->counter) {
151 dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
152 (dst->counter + src->counter);
153 }
154 dst->counter += src->counter;
155 dst->end_time = src->end_time;
156 if (dst->start_time == 0) {
157 dst->start_time = src->start_time;
158 }
159}
160
161bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) {
162 CHECK(ext_csd_fd >= 0);
163 struct hex {
164 char str[2];
165 };
166 // List of interesting offsets
167 static const size_t EXT_CSD_REV_IDX = 192 * sizeof(hex);
168 static const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(hex);
169 static const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(hex);
170 static const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(hex);
171
172 // Read file
173 CHECK(lseek(ext_csd_fd, 0, SEEK_SET) == 0);
174 std::string buffer;
175 if (!android::base::ReadFdToString(ext_csd_fd, &buffer)) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800176 PLOG_TO(SYSTEM, ERROR) << "ReadFdToString failed.";
ynwang62cb3722016-06-17 14:30:48 -0700177 return false;
178 }
179
180 if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800181 LOG_TO(SYSTEM, ERROR) << "EMMC ext csd file has truncated content. "
182 << "File length: " << buffer.length();
ynwang62cb3722016-06-17 14:30:48 -0700183 return false;
184 }
185
186 std::string sub;
187 std::stringstream ss;
188 // Parse EXT_CSD_REV
189 int ext_csd_rev = -1;
190 sub = buffer.substr(EXT_CSD_REV_IDX, sizeof(hex));
191 ss << sub;
192 ss >> std::hex >> ext_csd_rev;
193 if (ext_csd_rev < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800194 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV.";
ynwang62cb3722016-06-17 14:30:48 -0700195 return false;
196 }
197 ss.clear();
198
199 static const char* ver_str[] = {
200 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
201 };
202
Jin Qianb00d5462017-01-17 15:08:00 -0800203 strlcpy(info->mmc_ver,
ynwang62cb3722016-06-17 14:30:48 -0700204 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
205 ver_str[ext_csd_rev] :
206 "Unknown",
207 MMC_VER_STR_LEN);
208
209 if (ext_csd_rev < 7) {
210 return 0;
211 }
212
213 // Parse EXT_PRE_EOL_INFO
214 info->eol = -1;
215 sub = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(hex));
216 ss << sub;
217 ss >> std::hex >> info->eol;
218 if (info->eol < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800219 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO.";
ynwang62cb3722016-06-17 14:30:48 -0700220 return false;
221 }
222 ss.clear();
223
224 // Parse DEVICE_LIFE_TIME_EST
225 info->lifetime_a = -1;
226 sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(hex));
227 ss << sub;
228 ss >> std::hex >> info->lifetime_a;
229 if (info->lifetime_a < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800230 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A.";
ynwang62cb3722016-06-17 14:30:48 -0700231 return false;
232 }
233 ss.clear();
234
235 info->lifetime_b = -1;
236 sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(hex));
237 ss << sub;
238 ss >> std::hex >> info->lifetime_b;
239 if (info->lifetime_b < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800240 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B.";
ynwang62cb3722016-06-17 14:30:48 -0700241 return false;
242 }
243 ss.clear();
244
245 return true;
246}
247
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800248static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
249 // Compare background I/O first.
Jin Qian5b962c62017-01-30 14:48:38 -0800250 for (int i = UID_STATS - 1; i >= 0; i--) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800251 uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
252 uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes;
253 uint64_t l_chars = l.io[i].rchar + l.io[i].wchar;
254 uint64_t r_chars = r.io[i].rchar + r.io[i].wchar;
255
256 if (l_bytes != r_bytes) {
257 return l_bytes > r_bytes;
258 }
259 if (l_chars != r_chars) {
260 return l_chars > r_chars;
261 }
262 }
263
264 return l.name < r.name;
265}
266
267void sort_running_uids_info(std::vector<struct uid_info> &uids) {
268 std::sort(uids.begin(), uids.end(), cmp_uid_info);
269}
270
271// Logging functions
272void log_console_running_uids_info(std::vector<struct uid_info> uids) {
Jin Qian4bcc8b62017-03-14 12:40:06 -0700273 printf("name/uid fg_rchar fg_wchar fg_rbytes fg_wbytes "
274 "bg_rchar bg_wchar bg_rbytes bg_wbytes fg_fsync bg_fsync\n");
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800275
276 for (const auto& uid : uids) {
Jin Qian4bcc8b62017-03-14 12:40:06 -0700277 printf("%s %ju %ju %ju %ju %ju %ju %ju %ju %ju %ju\n", uid.name.c_str(),
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800278 uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes,
Jin Qiane83a6102017-03-02 16:16:54 -0800279 uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes,
280 uid.io[0].fsync, uid.io[1].fsync);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800281 }
282 fflush(stdout);
283}
284
Jin Qian27506fa2017-01-17 11:51:51 -0800285#if DEBUG
286void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
ynwang62cb3722016-06-17 14:30:48 -0700287 // skip if the input structure are all zeros
288 if (perf == NULL) return;
289 struct disk_perf zero_cmp;
290 memset(&zero_cmp, 0, sizeof(zero_cmp));
291 if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
292
Jin Qian535ddbe2017-01-11 17:19:21 -0800293 LOG_TO(SYSTEM, INFO) << "perf(ios) " << type
294 << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)"
295 << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)"
296 << " q:" << perf->queue;
ynwang62cb3722016-06-17 14:30:48 -0700297}
Jin Qian27506fa2017-01-17 11:51:51 -0800298#else
299void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {}
300#endif
ynwang62cb3722016-06-17 14:30:48 -0700301
302void log_event_disk_stats(struct disk_stats* stats, const char* type) {
303 // skip if the input structure are all zeros
304 if (stats == NULL) return;
305 struct disk_stats zero_cmp;
306 memset(&zero_cmp, 0, sizeof(zero_cmp));
307 // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
308 if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
309
Jin Qian535ddbe2017-01-11 17:19:21 -0800310 android_log_event_list(EVENTLOGTAG_DISKSTATS)
311 << type << stats->start_time << stats->end_time
312 << stats->read_ios << stats->read_merges
313 << stats->read_sectors << stats->read_ticks
314 << stats->write_ios << stats->write_merges
315 << stats->write_sectors << stats->write_ticks
316 << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
317 << LOG_ID_EVENTS;
ynwang62cb3722016-06-17 14:30:48 -0700318}
319
320void log_event_emmc_info(struct emmc_info* info) {
321 // skip if the input structure are all zeros
322 if (info == NULL) return;
323 struct emmc_info zero_cmp;
324 memset(&zero_cmp, 0, sizeof(zero_cmp));
325 if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
326
Jin Qian535ddbe2017-01-11 17:19:21 -0800327 android_log_event_list(EVENTLOGTAG_EMMCINFO)
328 << info->mmc_ver << info->eol << info->lifetime_a << info->lifetime_b
329 << LOG_ID_EVENTS;
ynwang62cb3722016-06-17 14:30:48 -0700330}