ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 19 | #include <dirent.h> |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 20 | #include <fcntl.h> |
| 21 | #include <linux/time.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 22 | #include <stdint.h> |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 23 | #include <stdio.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 24 | #include <stdlib.h> |
| 25 | #include <string.h> |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 26 | #include <sys/stat.h> |
| 27 | #include <time.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 28 | #include <unistd.h> |
| 29 | |
Jin Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 30 | #include <iomanip> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 31 | #include <sstream> |
| 32 | #include <string> |
| 33 | #include <unordered_map> |
| 34 | |
| 35 | #include <android-base/file.h> |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 36 | #include <android-base/logging.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 37 | #include <android-base/stringprintf.h> |
| 38 | #include <android-base/strings.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 39 | #include <log/log_event_list.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 40 | |
| 41 | #include <storaged.h> |
| 42 | #include <storaged_utils.h> |
| 43 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 44 | #define SECTOR_SIZE ( 512 ) |
| 45 | #define SEC_TO_MSEC ( 1000 ) |
| 46 | #define MSEC_TO_USEC ( 1000 ) |
| 47 | #define USEC_TO_NSEC ( 1000 ) |
| 48 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 49 | bool 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 56 | PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 57 | return false; |
| 58 | } |
| 59 | |
| 60 | std::string buffer; |
| 61 | if (!android::base::ReadFileToString(disk_stats_path, &buffer)) { |
Jin Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 62 | PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed."; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 63 | 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 | |
| 80 | struct 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 | |
| 117 | struct 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 |
| 139 | void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) { |
Jin Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 140 | 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; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 144 | } |
| 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 | |
| 166 | bool 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 181 | PLOG_TO(SYSTEM, ERROR) << "ReadFdToString failed."; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 182 | return false; |
| 183 | } |
| 184 | |
| 185 | if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) { |
Jin Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 186 | LOG_TO(SYSTEM, ERROR) << "EMMC ext csd file has truncated content. " |
| 187 | << "File length: " << buffer.length(); |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 188 | 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 199 | LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV."; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 200 | 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 224 | LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO."; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 225 | 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 235 | LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A."; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 236 | 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 245 | LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B."; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 246 | 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 |
| 255 | bool 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 | |
| 297 | static 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 | |
| 307 | static 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 | |
| 321 | std::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 | |
| 340 | static 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 | |
| 354 | void 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 | } |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 378 | { // update critical area |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 379 | // 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 | |
| 387 | std::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 | |
| 409 | void 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 */ |
| 414 | void 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 | |
| 438 | void 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 445 | 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; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 453 | } |
| 454 | |
| 455 | void 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 462 | 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; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 466 | } |
| 467 | |
| 468 | void 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 475 | LOG_TO(SYSTEM, INFO) << "MMC " << info->mmc_ver << " eol:" << info->eol << ", " |
| 476 | << "lifetime typA:" << info->lifetime_a |
| 477 | << ", typB:" << info->lifetime_b; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 478 | } |
| 479 | |
| 480 | void 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 488 | 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; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 496 | } |
| 497 | |
| 498 | void 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 Qian | 535ddbe | 2017-01-11 17:19:21 -0800 | [diff] [blame^] | 505 | android_log_event_list(EVENTLOGTAG_EMMCINFO) |
| 506 | << info->mmc_ver << info->eol << info->lifetime_a << info->lifetime_b |
| 507 | << LOG_ID_EVENTS; |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 508 | } |