| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/process/process_metrics.h" | 5 #include "base/process/process_metrics.h" |
| 6 | 6 |
| 7 #include <dirent.h> | 7 #include <dirent.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #include <sys/time.h> | 10 #include <sys/time.h> |
| 11 #include <sys/types.h> | 11 #include <sys/types.h> |
| 12 #include <unistd.h> | 12 #include <unistd.h> |
| 13 | 13 |
| 14 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/process/internal_linux.h" | 16 #include "base/process/internal_linux.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/string_split.h" | 18 #include "base/strings/string_split.h" |
| 19 #include "base/strings/string_tokenizer.h" | 19 #include "base/strings/string_tokenizer.h" |
| 20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 21 #include "base/sys_info.h" | 21 #include "base/sys_info.h" |
| 22 #include "base/threading/thread_restrictions.h" | 22 #include "base/threading/thread_restrictions.h" |
| 23 | 23 |
| 24 namespace base { | 24 namespace base { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 enum ParsingState { | 28 #if defined(OS_CHROMEOS) |
| 29 KEY_NAME, | |
| 30 KEY_VALUE | |
| 31 }; | |
| 32 | |
| 33 #ifdef OS_CHROMEOS | |
| 34 // Read a file with a single number string and return the number as a uint64. | 29 // Read a file with a single number string and return the number as a uint64. |
| 35 static uint64 ReadFileToUint64(const base::FilePath file) { | 30 static uint64 ReadFileToUint64(const FilePath file) { |
| 36 std::string file_as_string; | 31 std::string file_as_string; |
| 37 if (!ReadFileToString(file, &file_as_string)) | 32 if (!ReadFileToString(file, &file_as_string)) |
| 38 return 0; | 33 return 0; |
| 39 base::TrimWhitespaceASCII(file_as_string, base::TRIM_ALL, &file_as_string); | 34 TrimWhitespaceASCII(file_as_string, TRIM_ALL, &file_as_string); |
| 40 uint64 file_as_uint64 = 0; | 35 uint64 file_as_uint64 = 0; |
| 41 if (!base::StringToUint64(file_as_string, &file_as_uint64)) | 36 if (!StringToUint64(file_as_string, &file_as_uint64)) |
| 42 return 0; | 37 return 0; |
| 43 return file_as_uint64; | 38 return file_as_uint64; |
| 44 } | 39 } |
| 45 #endif | 40 #endif |
| 46 | 41 |
| 47 // Read /proc/<pid>/status and returns the value for |field|, or 0 on failure. | 42 // Read /proc/<pid>/status and return the value for |field|, or 0 on failure. |
| 48 // Only works for fields in the form of "Field: value kB". | 43 // Only works for fields in the form of "Field: value kB". |
| 49 size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { | 44 size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { |
| 50 FilePath stat_file = internal::GetProcPidDir(pid).Append("status"); | |
| 51 std::string status; | 45 std::string status; |
| 52 { | 46 { |
| 53 // Synchronously reading files in /proc is safe. | 47 // Synchronously reading files in /proc is safe. |
| 54 ThreadRestrictions::ScopedAllowIO allow_io; | 48 ThreadRestrictions::ScopedAllowIO allow_io; |
| 49 FilePath stat_file = internal::GetProcPidDir(pid).Append("status"); |
| 55 if (!ReadFileToString(stat_file, &status)) | 50 if (!ReadFileToString(stat_file, &status)) |
| 56 return 0; | 51 return 0; |
| 57 } | 52 } |
| 58 | 53 |
| 59 StringTokenizer tokenizer(status, ":\n"); | 54 std::vector<std::pair<std::string, std::string> > pairs; |
| 60 ParsingState state = KEY_NAME; | 55 SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs); |
| 61 StringPiece last_key_name; | 56 for (size_t i = 0; i < pairs.size(); ++i) { |
| 62 while (tokenizer.GetNext()) { | 57 std::string key, value_str; |
| 63 switch (state) { | 58 TrimWhitespaceASCII(pairs[i].first, TRIM_ALL, &key); |
| 64 case KEY_NAME: | 59 TrimWhitespaceASCII(pairs[i].second, TRIM_ALL, &value_str); |
| 65 last_key_name = tokenizer.token_piece(); | 60 if (key == field) { |
| 66 state = KEY_VALUE; | 61 std::vector<std::string> split_value_str; |
| 67 break; | 62 SplitString(value_str, ' ', &split_value_str); |
| 68 case KEY_VALUE: | 63 if (split_value_str.size() != 2 || split_value_str[1] != "kB") { |
| 69 DCHECK(!last_key_name.empty()); | 64 NOTREACHED(); |
| 70 if (last_key_name == field) { | 65 return 0; |
| 71 std::string value_str; | 66 } |
| 72 tokenizer.token_piece().CopyToString(&value_str); | 67 size_t value; |
| 73 std::string value_str_trimmed; | 68 if (!StringToSizeT(split_value_str[0], &value)) { |
| 74 base::TrimWhitespaceASCII(value_str, base::TRIM_ALL, | 69 NOTREACHED(); |
| 75 &value_str_trimmed); | 70 return 0; |
| 76 std::vector<std::string> split_value_str; | 71 } |
| 77 SplitString(value_str_trimmed, ' ', &split_value_str); | 72 return value; |
| 78 if (split_value_str.size() != 2 || split_value_str[1] != "kB") { | |
| 79 NOTREACHED(); | |
| 80 return 0; | |
| 81 } | |
| 82 size_t value; | |
| 83 if (!StringToSizeT(split_value_str[0], &value)) { | |
| 84 NOTREACHED(); | |
| 85 return 0; | |
| 86 } | |
| 87 return value; | |
| 88 } | |
| 89 state = KEY_NAME; | |
| 90 break; | |
| 91 } | 73 } |
| 92 } | 74 } |
| 93 NOTREACHED(); | 75 NOTREACHED(); |
| 94 return 0; | 76 return 0; |
| 95 } | 77 } |
| 96 | 78 |
| 97 // Get the total CPU of a single process. Return value is number of jiffies | 79 // Get the total CPU of a single process. Return value is number of jiffies |
| 98 // on success or -1 on error. | 80 // on success or -1 on error. |
| 99 int GetProcessCPU(pid_t pid) { | 81 int GetProcessCPU(pid_t pid) { |
| 100 // Use /proc/<pid>/task to find all threads and parse their /stat file. | 82 // Use /proc/<pid>/task to find all threads and parse their /stat file. |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 // in your kernel configuration. | 198 // in your kernel configuration. |
| 217 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { | 199 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
| 218 // Synchronously reading files in /proc is safe. | 200 // Synchronously reading files in /proc is safe. |
| 219 ThreadRestrictions::ScopedAllowIO allow_io; | 201 ThreadRestrictions::ScopedAllowIO allow_io; |
| 220 | 202 |
| 221 std::string proc_io_contents; | 203 std::string proc_io_contents; |
| 222 FilePath io_file = internal::GetProcPidDir(process_).Append("io"); | 204 FilePath io_file = internal::GetProcPidDir(process_).Append("io"); |
| 223 if (!ReadFileToString(io_file, &proc_io_contents)) | 205 if (!ReadFileToString(io_file, &proc_io_contents)) |
| 224 return false; | 206 return false; |
| 225 | 207 |
| 226 (*io_counters).OtherOperationCount = 0; | 208 io_counters->OtherOperationCount = 0; |
| 227 (*io_counters).OtherTransferCount = 0; | 209 io_counters->OtherTransferCount = 0; |
| 228 | 210 |
| 229 StringTokenizer tokenizer(proc_io_contents, ": \n"); | 211 std::vector<std::pair<std::string, std::string> > pairs; |
| 230 ParsingState state = KEY_NAME; | 212 SplitStringIntoKeyValuePairs(proc_io_contents, ':', '\n', &pairs); |
| 231 StringPiece last_key_name; | 213 for (size_t i = 0; i < pairs.size(); ++i) { |
| 232 while (tokenizer.GetNext()) { | 214 std::string key, value_str; |
| 233 switch (state) { | 215 TrimWhitespaceASCII(pairs[i].first, TRIM_ALL, &key); |
| 234 case KEY_NAME: | 216 TrimWhitespaceASCII(pairs[i].second, TRIM_ALL, &value_str); |
| 235 last_key_name = tokenizer.token_piece(); | 217 uint64* target_counter = NULL; |
| 236 state = KEY_VALUE; | 218 if (key == "syscr") |
| 237 break; | 219 target_counter = &io_counters->ReadOperationCount; |
| 238 case KEY_VALUE: | 220 else if (key == "syscw") |
| 239 DCHECK(!last_key_name.empty()); | 221 target_counter = &io_counters->WriteOperationCount; |
| 240 if (last_key_name == "syscr") { | 222 else if (key == "rchar") |
| 241 StringToInt64(tokenizer.token_piece(), | 223 target_counter = &io_counters->ReadTransferCount; |
| 242 reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount)); | 224 else if (key == "wchar") |
| 243 } else if (last_key_name == "syscw") { | 225 target_counter = &io_counters->WriteTransferCount; |
| 244 StringToInt64(tokenizer.token_piece(), | 226 if (!target_counter) |
| 245 reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount)); | 227 continue; |
| 246 } else if (last_key_name == "rchar") { | 228 bool converted = StringToUint64(value_str, target_counter); |
| 247 StringToInt64(tokenizer.token_piece(), | 229 DCHECK(converted); |
| 248 reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount)); | |
| 249 } else if (last_key_name == "wchar") { | |
| 250 StringToInt64(tokenizer.token_piece(), | |
| 251 reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount)); | |
| 252 } | |
| 253 state = KEY_NAME; | |
| 254 break; | |
| 255 } | |
| 256 } | 230 } |
| 257 return true; | 231 return true; |
| 258 } | 232 } |
| 259 | 233 |
| 260 ProcessMetrics::ProcessMetrics(ProcessHandle process) | 234 ProcessMetrics::ProcessMetrics(ProcessHandle process) |
| 261 : process_(process), | 235 : process_(process), |
| 262 last_system_time_(0), | 236 last_system_time_(0), |
| 263 last_cpu_(0) { | 237 last_cpu_(0) { |
| 264 processor_count_ = base::SysInfo::NumberOfProcessors(); | 238 processor_count_ = SysInfo::NumberOfProcessors(); |
| 265 } | 239 } |
| 266 | 240 |
| 267 #if defined(OS_CHROMEOS) | 241 #if defined(OS_CHROMEOS) |
| 268 // Private, Shared and Proportional working set sizes are obtained from | 242 // Private, Shared and Proportional working set sizes are obtained from |
| 269 // /proc/<pid>/totmaps | 243 // /proc/<pid>/totmaps |
| 270 bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) | 244 bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) |
| 271 const { | 245 const { |
| 272 // The format of /proc/<pid>/totmaps is: | 246 // The format of /proc/<pid>/totmaps is: |
| 273 // | 247 // |
| 274 // Rss: 6120 kB | 248 // Rss: 6120 kB |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 | 447 |
| 474 #ifdef OS_CHROMEOS | 448 #ifdef OS_CHROMEOS |
| 475 shmem = 0; | 449 shmem = 0; |
| 476 slab = 0; | 450 slab = 0; |
| 477 gem_objects = -1; | 451 gem_objects = -1; |
| 478 gem_size = -1; | 452 gem_size = -1; |
| 479 #endif | 453 #endif |
| 480 } | 454 } |
| 481 | 455 |
| 482 scoped_ptr<Value> SystemMemoryInfoKB::ToValue() const { | 456 scoped_ptr<Value> SystemMemoryInfoKB::ToValue() const { |
| 483 scoped_ptr<DictionaryValue> res(new base::DictionaryValue()); | 457 scoped_ptr<DictionaryValue> res(new DictionaryValue()); |
| 484 | 458 |
| 485 res->SetInteger("total", total); | 459 res->SetInteger("total", total); |
| 486 res->SetInteger("free", free); | 460 res->SetInteger("free", free); |
| 487 res->SetInteger("buffers", buffers); | 461 res->SetInteger("buffers", buffers); |
| 488 res->SetInteger("cached", cached); | 462 res->SetInteger("cached", cached); |
| 489 res->SetInteger("active_anon", active_anon); | 463 res->SetInteger("active_anon", active_anon); |
| 490 res->SetInteger("inactive_anon", inactive_anon); | 464 res->SetInteger("inactive_anon", inactive_anon); |
| 491 res->SetInteger("active_file", active_file); | 465 res->SetInteger("active_file", active_file); |
| 492 res->SetInteger("inactive_file", inactive_file); | 466 res->SetInteger("inactive_file", inactive_file); |
| 493 res->SetInteger("swap_total", swap_total); | 467 res->SetInteger("swap_total", swap_total); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 meminfo->total = 0; | 499 meminfo->total = 0; |
| 526 | 500 |
| 527 std::vector<std::string> meminfo_lines; | 501 std::vector<std::string> meminfo_lines; |
| 528 Tokenize(meminfo_data, "\n", &meminfo_lines); | 502 Tokenize(meminfo_data, "\n", &meminfo_lines); |
| 529 for (std::vector<std::string>::iterator it = meminfo_lines.begin(); | 503 for (std::vector<std::string>::iterator it = meminfo_lines.begin(); |
| 530 it != meminfo_lines.end(); ++it) { | 504 it != meminfo_lines.end(); ++it) { |
| 531 std::vector<std::string> tokens; | 505 std::vector<std::string> tokens; |
| 532 SplitStringAlongWhitespace(*it, &tokens); | 506 SplitStringAlongWhitespace(*it, &tokens); |
| 533 // HugePages_* only has a number and no suffix so we can't rely on | 507 // HugePages_* only has a number and no suffix so we can't rely on |
| 534 // there being exactly 3 tokens. | 508 // there being exactly 3 tokens. |
| 535 if (tokens.size() > 1) { | 509 if (tokens.size() <= 1) { |
| 536 if (tokens[0] == "MemTotal:") { | |
| 537 StringToInt(tokens[1], &meminfo->total); | |
| 538 continue; | |
| 539 } if (tokens[0] == "MemFree:") { | |
| 540 StringToInt(tokens[1], &meminfo->free); | |
| 541 continue; | |
| 542 } if (tokens[0] == "Buffers:") { | |
| 543 StringToInt(tokens[1], &meminfo->buffers); | |
| 544 continue; | |
| 545 } if (tokens[0] == "Cached:") { | |
| 546 StringToInt(tokens[1], &meminfo->cached); | |
| 547 continue; | |
| 548 } if (tokens[0] == "Active(anon):") { | |
| 549 StringToInt(tokens[1], &meminfo->active_anon); | |
| 550 continue; | |
| 551 } if (tokens[0] == "Inactive(anon):") { | |
| 552 StringToInt(tokens[1], &meminfo->inactive_anon); | |
| 553 continue; | |
| 554 } if (tokens[0] == "Active(file):") { | |
| 555 StringToInt(tokens[1], &meminfo->active_file); | |
| 556 continue; | |
| 557 } if (tokens[0] == "Inactive(file):") { | |
| 558 StringToInt(tokens[1], &meminfo->inactive_file); | |
| 559 continue; | |
| 560 } if (tokens[0] == "SwapTotal:") { | |
| 561 StringToInt(tokens[1], &meminfo->swap_total); | |
| 562 continue; | |
| 563 } if (tokens[0] == "SwapFree:") { | |
| 564 StringToInt(tokens[1], &meminfo->swap_free); | |
| 565 continue; | |
| 566 } if (tokens[0] == "Dirty:") { | |
| 567 StringToInt(tokens[1], &meminfo->dirty); | |
| 568 continue; | |
| 569 #if defined(OS_CHROMEOS) | |
| 570 // Chrome OS has a tweaked kernel that allows us to query Shmem, which is | |
| 571 // usually video memory otherwise invisible to the OS. | |
| 572 } if (tokens[0] == "Shmem:") { | |
| 573 StringToInt(tokens[1], &meminfo->shmem); | |
| 574 continue; | |
| 575 } if (tokens[0] == "Slab:") { | |
| 576 StringToInt(tokens[1], &meminfo->slab); | |
| 577 continue; | |
| 578 #endif | |
| 579 } | |
| 580 } else | |
| 581 DLOG(WARNING) << "meminfo: tokens: " << tokens.size() | 510 DLOG(WARNING) << "meminfo: tokens: " << tokens.size() |
| 582 << " malformed line: " << *it; | 511 << " malformed line: " << *it; |
| 512 continue; |
| 513 } |
| 514 |
| 515 int* target = NULL; |
| 516 if (tokens[0] == "MemTotal:") |
| 517 target = &meminfo->total; |
| 518 else if (tokens[0] == "MemFree:") |
| 519 target = &meminfo->free; |
| 520 else if (tokens[0] == "Buffers:") |
| 521 target = &meminfo->buffers; |
| 522 else if (tokens[0] == "Cached:") |
| 523 target = &meminfo->cached; |
| 524 else if (tokens[0] == "Active(anon):") |
| 525 target = &meminfo->active_anon; |
| 526 else if (tokens[0] == "Inactive(anon):") |
| 527 target = &meminfo->inactive_anon; |
| 528 else if (tokens[0] == "Active(file):") |
| 529 target = &meminfo->active_file; |
| 530 else if (tokens[0] == "Inactive(file):") |
| 531 target = &meminfo->inactive_file; |
| 532 else if (tokens[0] == "SwapTotal:") |
| 533 target = &meminfo->swap_total; |
| 534 else if (tokens[0] == "SwapFree:") |
| 535 target = &meminfo->swap_free; |
| 536 else if (tokens[0] == "Dirty:") |
| 537 target = &meminfo->dirty; |
| 538 #if defined(OS_CHROMEOS) |
| 539 // Chrome OS has a tweaked kernel that allows us to query Shmem, which is |
| 540 // usually video memory otherwise invisible to the OS. |
| 541 else if (tokens[0] == "Shmem:") |
| 542 target = &meminfo->shmem; |
| 543 else if (tokens[0] == "Slab:") |
| 544 target = &meminfo->slab; |
| 545 #endif |
| 546 if (target) |
| 547 StringToInt(tokens[1], target); |
| 583 } | 548 } |
| 584 | 549 |
| 585 // Make sure we got a valid MemTotal. | 550 // Make sure we got a valid MemTotal. |
| 586 if (!meminfo->total) | 551 return meminfo->total > 0; |
| 587 return false; | |
| 588 | |
| 589 return true; | |
| 590 } | 552 } |
| 591 | 553 |
| 592 // exposed for testing | 554 // exposed for testing |
| 593 bool ParseProcVmstat(const std::string& vmstat_data, | 555 bool ParseProcVmstat(const std::string& vmstat_data, |
| 594 SystemMemoryInfoKB* meminfo) { | 556 SystemMemoryInfoKB* meminfo) { |
| 595 // The format of /proc/vmstat is: | 557 // The format of /proc/vmstat is: |
| 596 // | 558 // |
| 597 // nr_free_pages 299878 | 559 // nr_free_pages 299878 |
| 598 // nr_inactive_anon 239863 | 560 // nr_inactive_anon 239863 |
| 599 // nr_active_anon 1318966 | 561 // nr_active_anon 1318966 |
| 600 // nr_inactive_file 2015629 | 562 // nr_inactive_file 2015629 |
| 601 // ... | 563 // ... |
| 602 // | 564 // |
| 603 // We iterate through the whole file because the position of the | 565 // We iterate through the whole file because the position of the |
| 604 // fields are dependent on the kernel version and configuration. | 566 // fields are dependent on the kernel version and configuration. |
| 605 | 567 |
| 606 std::vector<std::string> vmstat_lines; | 568 std::vector<std::string> vmstat_lines; |
| 607 Tokenize(vmstat_data, "\n", &vmstat_lines); | 569 Tokenize(vmstat_data, "\n", &vmstat_lines); |
| 608 for (std::vector<std::string>::iterator it = vmstat_lines.begin(); | 570 for (std::vector<std::string>::iterator it = vmstat_lines.begin(); |
| 609 it != vmstat_lines.end(); ++it) { | 571 it != vmstat_lines.end(); ++it) { |
| 610 std::vector<std::string> tokens; | 572 std::vector<std::string> tokens; |
| 611 SplitString(*it, ' ', &tokens); | 573 SplitString(*it, ' ', &tokens); |
| 612 if (tokens.size() == 2) { | 574 if (tokens.size() != 2) |
| 613 if (tokens[0] == "pswpin") { | 575 continue; |
| 614 StringToInt(tokens[1], &meminfo->pswpin); | 576 |
| 615 continue; | 577 if (tokens[0] == "pswpin") { |
| 616 } if (tokens[0] == "pswpout") { | 578 StringToInt(tokens[1], &meminfo->pswpin); |
| 617 StringToInt(tokens[1], &meminfo->pswpout); | 579 } else if (tokens[0] == "pswpout") { |
| 618 continue; | 580 StringToInt(tokens[1], &meminfo->pswpout); |
| 619 } if (tokens[0] == "pgmajfault") | 581 } else if (tokens[0] == "pgmajfault") { |
| 620 StringToInt(tokens[1], &meminfo->pgmajfault); | 582 StringToInt(tokens[1], &meminfo->pgmajfault); |
| 621 } | 583 } |
| 622 } | 584 } |
| 623 | 585 |
| 624 return true; | 586 return true; |
| 625 } | 587 } |
| 626 | 588 |
| 627 bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { | 589 bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { |
| 628 // Synchronously reading files in /proc is safe. | 590 // Synchronously reading files in /proc and /sys are safe. |
| 629 ThreadRestrictions::ScopedAllowIO allow_io; | 591 ThreadRestrictions::ScopedAllowIO allow_io; |
| 630 | 592 |
| 631 // Used memory is: total - free - buffers - caches | 593 // Used memory is: total - free - buffers - caches |
| 632 FilePath meminfo_file("/proc/meminfo"); | 594 FilePath meminfo_file("/proc/meminfo"); |
| 633 std::string meminfo_data; | 595 std::string meminfo_data; |
| 634 if (!ReadFileToString(meminfo_file, &meminfo_data)) { | 596 if (!ReadFileToString(meminfo_file, &meminfo_data)) { |
| 635 DLOG(WARNING) << "Failed to open " << meminfo_file.value(); | 597 DLOG(WARNING) << "Failed to open " << meminfo_file.value(); |
| 636 return false; | 598 return false; |
| 637 } | 599 } |
| 638 | 600 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 writes = 0; | 662 writes = 0; |
| 701 writes_merged = 0; | 663 writes_merged = 0; |
| 702 sectors_written = 0; | 664 sectors_written = 0; |
| 703 write_time = 0; | 665 write_time = 0; |
| 704 io = 0; | 666 io = 0; |
| 705 io_time = 0; | 667 io_time = 0; |
| 706 weighted_io_time = 0; | 668 weighted_io_time = 0; |
| 707 } | 669 } |
| 708 | 670 |
| 709 scoped_ptr<Value> SystemDiskInfo::ToValue() const { | 671 scoped_ptr<Value> SystemDiskInfo::ToValue() const { |
| 710 scoped_ptr<DictionaryValue> res(new base::DictionaryValue()); | 672 scoped_ptr<DictionaryValue> res(new DictionaryValue()); |
| 711 | 673 |
| 712 // Write out uint64 variables as doubles. | 674 // Write out uint64 variables as doubles. |
| 713 // Note: this may discard some precision, but for JS there's no other option. | 675 // Note: this may discard some precision, but for JS there's no other option. |
| 714 res->SetDouble("reads", static_cast<double>(reads)); | 676 res->SetDouble("reads", static_cast<double>(reads)); |
| 715 res->SetDouble("reads_merged", static_cast<double>(reads_merged)); | 677 res->SetDouble("reads_merged", static_cast<double>(reads_merged)); |
| 716 res->SetDouble("sectors_read", static_cast<double>(sectors_read)); | 678 res->SetDouble("sectors_read", static_cast<double>(sectors_read)); |
| 717 res->SetDouble("read_time", static_cast<double>(read_time)); | 679 res->SetDouble("read_time", static_cast<double>(read_time)); |
| 718 res->SetDouble("writes", static_cast<double>(writes)); | 680 res->SetDouble("writes", static_cast<double>(writes)); |
| 719 res->SetDouble("writes_merged", static_cast<double>(writes_merged)); | 681 res->SetDouble("writes_merged", static_cast<double>(writes_merged)); |
| 720 res->SetDouble("sectors_written", static_cast<double>(sectors_written)); | 682 res->SetDouble("sectors_written", static_cast<double>(sectors_written)); |
| 721 res->SetDouble("write_time", static_cast<double>(write_time)); | 683 res->SetDouble("write_time", static_cast<double>(write_time)); |
| 722 res->SetDouble("io", static_cast<double>(io)); | 684 res->SetDouble("io", static_cast<double>(io)); |
| 723 res->SetDouble("io_time", static_cast<double>(io_time)); | 685 res->SetDouble("io_time", static_cast<double>(io_time)); |
| 724 res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time)); | 686 res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time)); |
| 725 | 687 |
| 726 return res.PassAs<Value>(); | 688 return res.PassAs<Value>(); |
| 727 } | 689 } |
| 728 | 690 |
| 729 bool IsValidDiskName(const std::string& candidate) { | 691 bool IsValidDiskName(const std::string& candidate) { |
| 730 if (candidate.length() < 3) | 692 if (candidate.length() < 3) |
| 731 return false; | 693 return false; |
| 732 if (candidate.substr(0,2) == "sd" || candidate.substr(0,2) == "hd") { | 694 if (candidate[1] == 'd' && |
| 733 // [sh]d[a-z]+ case | 695 (candidate[0] == 'h' || candidate[0] == 's' || candidate[0] == 'v')) { |
| 734 for (size_t i = 2; i < candidate.length(); i++) { | 696 // [hsv]d[a-z]+ case |
| 697 for (size_t i = 2; i < candidate.length(); ++i) { |
| 735 if (!islower(candidate[i])) | 698 if (!islower(candidate[i])) |
| 736 return false; | 699 return false; |
| 737 } | 700 } |
| 738 } else { | 701 return true; |
| 739 if (candidate.length() < 7) { | |
| 740 return false; | |
| 741 } | |
| 742 if (candidate.substr(0,6) == "mmcblk") { | |
| 743 // mmcblk[0-9]+ case | |
| 744 for (size_t i = 6; i < candidate.length(); i++) { | |
| 745 if (!isdigit(candidate[i])) | |
| 746 return false; | |
| 747 } | |
| 748 } else { | |
| 749 return false; | |
| 750 } | |
| 751 } | 702 } |
| 752 | 703 |
| 704 const char kMMCName[] = "mmcblk"; |
| 705 const size_t kMMCNameLen = strlen(kMMCName); |
| 706 if (candidate.length() < kMMCNameLen + 1) |
| 707 return false; |
| 708 if (candidate.compare(0, kMMCNameLen, kMMCName) != 0) |
| 709 return false; |
| 710 |
| 711 // mmcblk[0-9]+ case |
| 712 for (size_t i = kMMCNameLen; i < candidate.length(); ++i) { |
| 713 if (!isdigit(candidate[i])) |
| 714 return false; |
| 715 } |
| 753 return true; | 716 return true; |
| 754 } | 717 } |
| 755 | 718 |
| 756 bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) { | 719 bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) { |
| 757 // Synchronously reading files in /proc is safe. | 720 // Synchronously reading files in /proc is safe. |
| 758 ThreadRestrictions::ScopedAllowIO allow_io; | 721 ThreadRestrictions::ScopedAllowIO allow_io; |
| 759 | 722 |
| 760 FilePath diskinfo_file("/proc/diskstats"); | 723 FilePath diskinfo_file("/proc/diskstats"); |
| 761 std::string diskinfo_data; | 724 std::string diskinfo_data; |
| 762 if (!ReadFileToString(diskinfo_file, &diskinfo_data)) { | 725 if (!ReadFileToString(diskinfo_file, &diskinfo_data)) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 else | 810 else |
| 848 res->SetDouble("compression_ratio", 0); | 811 res->SetDouble("compression_ratio", 0); |
| 849 | 812 |
| 850 return res.PassAs<Value>(); | 813 return res.PassAs<Value>(); |
| 851 } | 814 } |
| 852 | 815 |
| 853 void GetSwapInfo(SwapInfo* swap_info) { | 816 void GetSwapInfo(SwapInfo* swap_info) { |
| 854 // Synchronously reading files in /sys/block/zram0 is safe. | 817 // Synchronously reading files in /sys/block/zram0 is safe. |
| 855 ThreadRestrictions::ScopedAllowIO allow_io; | 818 ThreadRestrictions::ScopedAllowIO allow_io; |
| 856 | 819 |
| 857 base::FilePath zram_path("/sys/block/zram0"); | 820 FilePath zram_path("/sys/block/zram0"); |
| 858 uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size")); | 821 uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size")); |
| 859 if (orig_data_size <= 4096) { | 822 if (orig_data_size <= 4096) { |
| 860 // A single page is compressed at startup, and has a high compression | 823 // A single page is compressed at startup, and has a high compression |
| 861 // ratio. We ignore this as it doesn't indicate any real swapping. | 824 // ratio. We ignore this as it doesn't indicate any real swapping. |
| 862 swap_info->orig_data_size = 0; | 825 swap_info->orig_data_size = 0; |
| 863 swap_info->num_reads = 0; | 826 swap_info->num_reads = 0; |
| 864 swap_info->num_writes = 0; | 827 swap_info->num_writes = 0; |
| 865 swap_info->compr_data_size = 0; | 828 swap_info->compr_data_size = 0; |
| 866 swap_info->mem_used_total = 0; | 829 swap_info->mem_used_total = 0; |
| 867 return; | 830 return; |
| 868 } | 831 } |
| 869 swap_info->orig_data_size = orig_data_size; | 832 swap_info->orig_data_size = orig_data_size; |
| 870 swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads")); | 833 swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads")); |
| 871 swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes")); | 834 swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes")); |
| 872 swap_info->compr_data_size = | 835 swap_info->compr_data_size = |
| 873 ReadFileToUint64(zram_path.Append("compr_data_size")); | 836 ReadFileToUint64(zram_path.Append("compr_data_size")); |
| 874 swap_info->mem_used_total = | 837 swap_info->mem_used_total = |
| 875 ReadFileToUint64(zram_path.Append("mem_used_total")); | 838 ReadFileToUint64(zram_path.Append("mem_used_total")); |
| 876 } | 839 } |
| 877 #endif // defined(OS_CHROMEOS) | 840 #endif // defined(OS_CHROMEOS) |
| 878 | 841 |
| 879 } // namespace base | 842 } // namespace base |
| OLD | NEW |