blob: e91b1bb1db28acaaf63b4ab27e3bae29de3b7a72 [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 -070044#define SECTOR_SIZE ( 512 )
45#define SEC_TO_MSEC ( 1000 )
46#define MSEC_TO_USEC ( 1000 )
47#define USEC_TO_NSEC ( 1000 )
48
ynwang62cb3722016-06-17 14:30:48 -070049bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
50 // Get time
51 struct timespec ts;
52 // Use monotonic to exclude suspend time so that we measure IO bytes/sec
53 // when system is running.
54 int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
55 if (ret < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -080056 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
ynwang62cb3722016-06-17 14:30:48 -070057 return false;
58 }
59
60 std::string buffer;
61 if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
Jin Qian535ddbe2017-01-11 17:19:21 -080062 PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
ynwang62cb3722016-06-17 14:30:48 -070063 return false;
64 }
65
66 // Regular diskstats entries
67 std::stringstream ss(buffer);
68 for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
69 ss >> *((uint64_t*)stats + i);
70 }
71 // Other entries
72 stats->start_time = 0;
73 stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
74 ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
75 stats->counter = 1;
76 stats->io_avg = (double)stats->io_in_flight;
77 return true;
78}
79
80struct disk_perf get_disk_perf(struct disk_stats* stats) {
81 struct disk_perf perf;
82 memset(&perf, 0, sizeof(struct disk_perf)); // initialize
83
84 if (stats->io_ticks) {
85 if (stats->read_ticks) {
86 unsigned long long divisor = stats->read_ticks * stats->io_ticks;
87 perf.read_perf = ((unsigned long long)SECTOR_SIZE *
88 stats->read_sectors *
89 stats->io_in_queue +
90 (divisor >> 1)) /
91 divisor;
92 perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
93 stats->read_ios *
94 stats->io_in_queue +
95 (divisor >> 1)) /
96 divisor;
97 }
98 if (stats->write_ticks) {
99 unsigned long long divisor = stats->write_ticks * stats->io_ticks;
100 perf.write_perf = ((unsigned long long)SECTOR_SIZE *
101 stats->write_sectors *
102 stats->io_in_queue +
103 (divisor >> 1)) /
104 divisor;
105 perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
106 stats->write_ios *
107 stats->io_in_queue +
108 (divisor >> 1)) /
109 divisor;
110 }
111 perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
112 stats->io_ticks;
113 }
114 return perf;
115}
116
117struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
118 struct disk_stats inc;
119 for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
120 if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
121 continue;
122 }
123
124 *((uint64_t*)&inc + i) =
125 *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
126 }
127 // io_in_flight is exception
128 inc.io_in_flight = curr->io_in_flight;
129
130 inc.start_time = prev->end_time;
131 inc.end_time = curr->end_time;
132 inc.io_avg = curr->io_avg;
133 inc.counter = 1;
134
135 return inc;
136}
137
138// Add src to dst
139void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800140 if (dst->end_time != 0 && dst->end_time != src->start_time) {
141 LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
142 << " are added. dst end with " << dst->end_time
143 << ", src start with " << src->start_time;
ynwang62cb3722016-06-17 14:30:48 -0700144 }
145
146 for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
147 if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
148 continue;
149 }
150
151 *((uint64_t*)dst + i) += *((uint64_t*)src + i);
152 }
153
154 dst->io_in_flight = src->io_in_flight;
155 if (dst->counter + src->counter) {
156 dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
157 (dst->counter + src->counter);
158 }
159 dst->counter += src->counter;
160 dst->end_time = src->end_time;
161 if (dst->start_time == 0) {
162 dst->start_time = src->start_time;
163 }
164}
165
166bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) {
167 CHECK(ext_csd_fd >= 0);
168 struct hex {
169 char str[2];
170 };
171 // List of interesting offsets
172 static const size_t EXT_CSD_REV_IDX = 192 * sizeof(hex);
173 static const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(hex);
174 static const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(hex);
175 static const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(hex);
176
177 // Read file
178 CHECK(lseek(ext_csd_fd, 0, SEEK_SET) == 0);
179 std::string buffer;
180 if (!android::base::ReadFdToString(ext_csd_fd, &buffer)) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800181 PLOG_TO(SYSTEM, ERROR) << "ReadFdToString failed.";
ynwang62cb3722016-06-17 14:30:48 -0700182 return false;
183 }
184
185 if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800186 LOG_TO(SYSTEM, ERROR) << "EMMC ext csd file has truncated content. "
187 << "File length: " << buffer.length();
ynwang62cb3722016-06-17 14:30:48 -0700188 return false;
189 }
190
191 std::string sub;
192 std::stringstream ss;
193 // Parse EXT_CSD_REV
194 int ext_csd_rev = -1;
195 sub = buffer.substr(EXT_CSD_REV_IDX, sizeof(hex));
196 ss << sub;
197 ss >> std::hex >> ext_csd_rev;
198 if (ext_csd_rev < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800199 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV.";
ynwang62cb3722016-06-17 14:30:48 -0700200 return false;
201 }
202 ss.clear();
203
204 static const char* ver_str[] = {
205 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
206 };
207
208 strncpy(info->mmc_ver,
209 (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
210 ver_str[ext_csd_rev] :
211 "Unknown",
212 MMC_VER_STR_LEN);
213
214 if (ext_csd_rev < 7) {
215 return 0;
216 }
217
218 // Parse EXT_PRE_EOL_INFO
219 info->eol = -1;
220 sub = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(hex));
221 ss << sub;
222 ss >> std::hex >> info->eol;
223 if (info->eol < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800224 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO.";
ynwang62cb3722016-06-17 14:30:48 -0700225 return false;
226 }
227 ss.clear();
228
229 // Parse DEVICE_LIFE_TIME_EST
230 info->lifetime_a = -1;
231 sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(hex));
232 ss << sub;
233 ss >> std::hex >> info->lifetime_a;
234 if (info->lifetime_a < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800235 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A.";
ynwang62cb3722016-06-17 14:30:48 -0700236 return false;
237 }
238 ss.clear();
239
240 info->lifetime_b = -1;
241 sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(hex));
242 ss << sub;
243 ss >> std::hex >> info->lifetime_b;
244 if (info->lifetime_b < 0) {
Jin Qian535ddbe2017-01-11 17:19:21 -0800245 LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B.";
ynwang62cb3722016-06-17 14:30:48 -0700246 return false;
247 }
248 ss.clear();
249
250 return true;
251}
252
253#define PROC_DIR "/proc/"
254#define PROC_STAT_STARTTIME_IDX ( 22 ) // This index is 1 based according to the linux proc man page
255bool parse_task_info(uint32_t pid, struct task_info* info) {
256 std::string buffer;
257 std::string pid_str = std::to_string(pid);
258 info->pid = pid;
259
260 // Get task I/O
261 std::string task_io_path = android::base::StringPrintf(PROC_DIR "%s/io", pid_str.c_str());
262 if (!android::base::ReadFileToString(task_io_path, &buffer)) return false;
263
264 std::stringstream ss(buffer);
265 std::string title;
266
267 ss >> title >> info->rchar
268 >> title >> info->wchar
269 >> title >> info->syscr
270 >> title >> info->syscw
271 >> title >> info->read_bytes
272 >> title >> info->write_bytes
273 >> title >> info->cancelled_write_bytes;
274 ss.clear();
275
276 // Get cmd string
277 std::string task_cmdline_path = android::base::StringPrintf(PROC_DIR "%u/cmdline", pid);
278 if (!android::base::ReadFileToString(task_cmdline_path, &buffer)) return false;
279 strcpy(info->cmd, android::base::Trim(buffer).c_str());
280
281 if (info->cmd[0] == '\0') {
282 std::string task_comm_path = android::base::StringPrintf(PROC_DIR "%u/comm", pid);
283 if (!android::base::ReadFileToString(task_comm_path, &buffer)) return false;
284 strcpy(info->cmd, android::base::Trim(buffer).c_str());
285 }
286
287 // Get task start time
288 std::string task_stat_path = android::base::StringPrintf(PROC_DIR "%u/stat", pid);
289 if (!android::base::ReadFileToString(task_stat_path, &buffer)) return false;
290
291 std::vector<std::string> stat_parts = android::base::Split(buffer, " ");
292 info->starttime = atoll(stat_parts[PROC_STAT_STARTTIME_IDX - 1].c_str());
293
294 return true;
295}
296
297static bool is_pid(char* d_name) {
298 if (!d_name || d_name[0] == '\0') return false;
299 char* c = d_name;
300 while (*c) {
301 if (!isdigit(*c)) return false;
302 ++c;
303 }
304 return true;
305}
306
307static bool cmp_task_info(struct task_info i, struct task_info j) {
308 if (i.write_bytes + i.read_bytes != j.write_bytes + j.read_bytes) {
309 return i.write_bytes + i.read_bytes > j.write_bytes + j.read_bytes;
310 }
311 if (i.wchar + i.rchar != j.wchar + j.rchar) {
312 return i.wchar + i.rchar > j.wchar + j.rchar;
313 }
314 if (i.syscw + i.syscr != j.syscw + j.syscr) {
315 return i.syscw + i.syscr > j.syscw + j.syscr;
316 }
317
318 return strcmp(i.cmd, j.cmd) < 0;
319}
320
321std::unordered_map<uint32_t, struct task_info> tasks_t::get_running_tasks() {
322 std::unordered_map<uint32_t, struct task_info> retval;
323 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(PROC_DIR), closedir);
324 CHECK(dir != NULL);
325 struct dirent* dp;
326
327 for (;;) {
328 if ((dp = readdir(dir.get())) == NULL) break;
329 if (!is_pid(dp->d_name)) continue;
330
331 uint32_t pid = atol(dp->d_name);
332 struct task_info info;
333 if (parse_task_info(pid, &info)) {
334 retval[pid] = info;
335 }
336 }
337 return retval;
338}
339
340static void add_task_info(struct task_info* src, struct task_info* dst) {
341 CHECK(strcmp(src->cmd, dst->cmd) == 0);
342
343 dst->pid = 0;
344 dst->rchar += src->rchar;
345 dst->wchar += src->wchar;
346 dst->syscr += src->syscr;
347 dst->syscw += src->syscw;
348 dst->read_bytes += src->read_bytes;
349 dst->write_bytes += src->write_bytes;
350 dst->cancelled_write_bytes += src->cancelled_write_bytes;
351 dst->starttime = 0;
352}
353
354void tasks_t::update_running_tasks(void) {
355 std::unordered_map<uint32_t, struct task_info> tasks_latest = get_running_tasks();
356 std::unordered_map<std::string, struct task_info> tasks_old = mOld;
357
358 for (auto t : mRunning) {
359 uint32_t pid = t.first;
360 // old task on mRunning still exist on tasks_latest
361 if (tasks_latest.find(pid) != tasks_latest.end() &&
362 tasks_latest[pid].starttime == t.second.starttime) {
363 continue;
364 } else {
365 // This branch will handle 2 cases:
366 // - Task get killed between the 2 samplings
367 // - Task get killed and its pid is reused
368 std::string cmd = t.second.cmd;
369 struct task_info info = t.second;
370
371 if (tasks_old.find(cmd) == tasks_old.end()) {
372 tasks_old[cmd] = info;
373 } else {
374 add_task_info(&info, &tasks_old[cmd]);
375 }
376 }
377 }
ynwangaf49d972016-06-17 14:30:48 -0700378 { // update critical area
ynwang62cb3722016-06-17 14:30:48 -0700379 // this is really fast!
380 std::unique_ptr<lock_t> lock(new lock_t(&mSem));
381 mRunning = tasks_latest;
382 mOld = tasks_old;
383 }
384
385}
386
387std::vector<struct task_info> tasks_t::get_tasks(void) {
388 std::unique_ptr<lock_t> lock(new lock_t(&mSem));
389 std::unordered_map<std::string, struct task_info> tasks_map = mOld;
390
391 for (auto i : mRunning) {
392 std::string cmd = i.second.cmd;
393 if (tasks_map.find(cmd) == tasks_map.end()) {
394 tasks_map[cmd] = i.second;
395 } else {
396 add_task_info(&i.second, &tasks_map[cmd]);
397 }
398 }
399
400 std::vector<struct task_info> retval(tasks_map.size());
401 int idx = 0;
402 for (auto i : tasks_map) {
403 retval[idx++] = i.second;
404 }
405
406 return retval;
407}
408
409void sort_running_tasks_info(std::vector<struct task_info> &tasks) {
410 std::sort(tasks.begin(), tasks.end(), cmp_task_info);
411}
412
413/* Logging functions */
414void log_console_running_tasks_info(std::vector<struct task_info> tasks) {
415// Sample Output:
416// Application Read Write Read Write Read Write Cancelled
417// Name Characters Characters Syscalls Syscalls Bytes Bytes Writebytes
418// ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
419// zygote64 37688308 3388467 7607 4363 314519552 5373952 8192
420// system_server 95874193 2216913 74613 52257 213078016 7237632 16384
421// zygote 506279 1726194 921 263 128114688 1765376 0
422// /vendor/bin/qcks 75415632 75154382 21672 25036 63627264 29974528 10485760
423// /init 86658523 5107871 82113 8633 91015168 1245184 0
424
425 // Title
426 printf(" Application Read Write Read Write Read Write Cancelled\n"
427 " Name Characters Characters Syscalls Syscalls Bytes Bytes Writebytes\n"
428 " ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------\n");
429
430 for (struct task_info task : tasks) {
431 printf("%50s%15ju%15ju%15ju%15ju%15ju%15ju%15ju\n",
432 task.cmd, task.rchar, task.wchar, task.syscr, task.syscw,
433 task.read_bytes, task.write_bytes, task.cancelled_write_bytes);
434 }
435 fflush(stdout);
436}
437
438void log_kernel_disk_stats(struct disk_stats* stats, const char* type) {
439 // skip if the input structure are all zeros
440 if (stats == NULL) return;
441 struct disk_stats zero_cmp;
442 memset(&zero_cmp, 0, sizeof(zero_cmp));
443 if (memcmp(&zero_cmp, stats, sizeof(struct disk_stats)) == 0) return;
444
Jin Qian535ddbe2017-01-11 17:19:21 -0800445 LOG_TO(SYSTEM, INFO) << "diskstats " << type << ": "
446 << stats->start_time << " " << stats->end_time << " "
447 << stats->read_ios << " " << stats->read_merges << " "
448 << stats->read_sectors << " " << stats->read_ticks << " "
449 << stats->write_ios << " " << stats->write_merges << " "
450 << stats->write_sectors << " " << stats->write_ticks << " "
451 << std::setprecision(1) << std::fixed << stats->io_avg << " "
452 << stats->io_ticks << " " << stats->io_in_queue;
ynwang62cb3722016-06-17 14:30:48 -0700453}
454
455void log_kernel_disk_perf(struct disk_perf* perf, const char* type) {
456 // skip if the input structure are all zeros
457 if (perf == NULL) return;
458 struct disk_perf zero_cmp;
459 memset(&zero_cmp, 0, sizeof(zero_cmp));
460 if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
461
Jin Qian535ddbe2017-01-11 17:19:21 -0800462 LOG_TO(SYSTEM, INFO) << "perf(ios) " << type
463 << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)"
464 << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)"
465 << " q:" << perf->queue;
ynwang62cb3722016-06-17 14:30:48 -0700466}
467
468void log_kernel_emmc_info(struct emmc_info* info) {
469 // skip if the input structure are all zeros
470 if (info == NULL) return;
471 struct emmc_info zero_cmp;
472 memset(&zero_cmp, 0, sizeof(zero_cmp));
473 if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
474
Jin Qian535ddbe2017-01-11 17:19:21 -0800475 LOG_TO(SYSTEM, INFO) << "MMC " << info->mmc_ver << " eol:" << info->eol << ", "
476 << "lifetime typA:" << info->lifetime_a
477 << ", typB:" << info->lifetime_b;
ynwang62cb3722016-06-17 14:30:48 -0700478}
479
480void log_event_disk_stats(struct disk_stats* stats, const char* type) {
481 // skip if the input structure are all zeros
482 if (stats == NULL) return;
483 struct disk_stats zero_cmp;
484 memset(&zero_cmp, 0, sizeof(zero_cmp));
485 // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
486 if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
487
Jin Qian535ddbe2017-01-11 17:19:21 -0800488 android_log_event_list(EVENTLOGTAG_DISKSTATS)
489 << type << stats->start_time << stats->end_time
490 << stats->read_ios << stats->read_merges
491 << stats->read_sectors << stats->read_ticks
492 << stats->write_ios << stats->write_merges
493 << stats->write_sectors << stats->write_ticks
494 << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
495 << LOG_ID_EVENTS;
ynwang62cb3722016-06-17 14:30:48 -0700496}
497
498void log_event_emmc_info(struct emmc_info* info) {
499 // skip if the input structure are all zeros
500 if (info == NULL) return;
501 struct emmc_info zero_cmp;
502 memset(&zero_cmp, 0, sizeof(zero_cmp));
503 if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
504
Jin Qian535ddbe2017-01-11 17:19:21 -0800505 android_log_event_list(EVENTLOGTAG_EMMCINFO)
506 << info->mmc_ver << info->eol << info->lifetime_a << info->lifetime_b
507 << LOG_ID_EVENTS;
ynwang62cb3722016-06-17 14:30:48 -0700508}