process_metrics_linux.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
19682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Copyright (c) 2013 The Chromium Authors. All rights reserved.
29682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Use of this source code is governed by a BSD-style license that can be
39682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// found in the LICENSE file.
49682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
59682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/process/process_metrics.h"
69682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
79682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <dirent.h>
89682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <fcntl.h>
99682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <sys/stat.h>
109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <sys/time.h>
119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <sys/types.h>
129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <unistd.h>
139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/file_util.h"
159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/logging.h"
169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/process/internal_linux.h"
179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/strings/string_number_conversions.h"
189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/strings/string_split.h"
199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/strings/string_tokenizer.h"
209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/strings/string_util.h"
219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/sys_info.h"
229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "base/threading/thread_restrictions.h"
239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallnamespace base {
259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallnamespace {
279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallenum ParsingState {
299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  KEY_NAME,
309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  KEY_VALUE
319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall};
329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef OS_CHROMEOS
349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Read a file with a single number string and return the number as a uint64.
359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic uint64 ReadFileToUint64(const base::FilePath file) {
369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string file_as_string;
379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ReadFileToString(file, &file_as_string))
389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return 0;
399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  base::TrimWhitespaceASCII(file_as_string, base::TRIM_ALL, &file_as_string);
409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 file_as_uint64 = 0;
419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!base::StringToUint64(file_as_string, &file_as_uint64))
429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return 0;
439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return file_as_uint64;
449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Read /proc/<pid>/status and returns the value for |field|, or 0 on failure.
489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Only works for fields in the form of "Field: value kB".
499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath stat_file = internal::GetProcPidDir(pid).Append("status");
519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string status;
529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  {
539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // Synchronously reading files in /proc is safe.
549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    ThreadRestrictions::ScopedAllowIO allow_io;
559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (!ReadFileToString(stat_file, &status))
569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      return 0;
579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  StringTokenizer tokenizer(status, ":\n");
609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ParsingState state = KEY_NAME;
619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  StringPiece last_key_name;
629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  while (tokenizer.GetNext()) {
639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    switch (state) {
649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      case KEY_NAME:
659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        last_key_name = tokenizer.token_piece();
669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        state = KEY_VALUE;
679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        break;
689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      case KEY_VALUE:
699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        DCHECK(!last_key_name.empty());
709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        if (last_key_name == field) {
719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          std::string value_str;
729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          tokenizer.token_piece().CopyToString(&value_str);
739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          std::string value_str_trimmed;
749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          base::TrimWhitespaceASCII(value_str, base::TRIM_ALL,
759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                    &value_str_trimmed);
769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          std::vector<std::string> split_value_str;
779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          SplitString(value_str_trimmed, ' ', &split_value_str);
789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            NOTREACHED();
809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            return 0;
819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          }
829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          size_t value;
839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          if (!StringToSizeT(split_value_str[0], &value)) {
849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            NOTREACHED();
859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            return 0;
869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          }
879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          return value;
889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        }
899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        state = KEY_NAME;
909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        break;
919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  NOTREACHED();
949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return 0;
959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Get the total CPU of a single process.  Return value is number of jiffies
989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// on success or -1 on error.
999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallint GetProcessCPU(pid_t pid) {
1009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Use /proc/<pid>/task to find all threads and parse their /stat file.
1019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath task_path = internal::GetProcPidDir(pid).Append("task");
1029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  DIR* dir = opendir(task_path.value().c_str());
1049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!dir) {
1059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DPLOG(ERROR) << "opendir(" << task_path.value() << ")";
1069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return -1;
1079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
1089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int total_cpu = 0;
1109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  while (struct dirent* ent = readdir(dir)) {
1119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    pid_t tid = internal::ProcDirSlotToPid(ent->d_name);
1129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (!tid)
1139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      continue;
1149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // Synchronously reading files in /proc is safe.
1169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    ThreadRestrictions::ScopedAllowIO allow_io;
1179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    std::string stat;
1199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    FilePath stat_path =
1209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        task_path.Append(ent->d_name).Append(internal::kStatFile);
1219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (ReadFileToString(stat_path, &stat)) {
1229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      int cpu = ParseProcStatCPU(stat);
1239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      if (cpu > 0)
1249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        total_cpu += cpu;
1259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
1269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
1279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  closedir(dir);
1289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return total_cpu;
1309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}  // namespace
1339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// static
1359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
1369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return new ProcessMetrics(process);
1379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// On linux, we return vsize.
1409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t ProcessMetrics::GetPagefileUsage() const {
1419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return internal::ReadProcStatsAndGetFieldAsSizeT(process_,
1429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                                   internal::VM_VSIZE);
1439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// On linux, we return the high water mark of vsize.
1469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t ProcessMetrics::GetPeakPagefileUsage() const {
1479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return ReadProcStatusAndGetFieldAsSizeT(process_, "VmPeak") * 1024;
1489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// On linux, we return RSS.
1519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t ProcessMetrics::GetWorkingSetSize() const {
1529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) *
1539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      getpagesize();
1549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// On linux, we return the high water mark of RSS.
1579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t ProcessMetrics::GetPeakWorkingSetSize() const {
1589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return ReadProcStatusAndGetFieldAsSizeT(process_, "VmHWM") * 1024;
1599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
1629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                    size_t* shared_bytes) {
1639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  WorkingSetKBytes ws_usage;
1649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!GetWorkingSetKBytes(&ws_usage))
1659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
1669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (private_bytes)
1689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    *private_bytes = ws_usage.priv * 1024;
1699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (shared_bytes)
1719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    *shared_bytes = ws_usage.shared * 1024;
1729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
1749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
1779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(OS_CHROMEOS)
1789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (GetWorkingSetKBytesTotmaps(ws_usage))
1799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return true;
1809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
1819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return GetWorkingSetKBytesStatm(ws_usage);
1829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halldouble ProcessMetrics::GetCPUUsage() {
1859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  TimeTicks time = TimeTicks::Now();
1869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (last_cpu_ == 0) {
1889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // First call, just set the last values.
1899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    last_cpu_time_ = time;
1909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    last_cpu_ = GetProcessCPU(process_);
1919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return 0;
1929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
1939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
1959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  DCHECK_NE(time_delta, 0);
1969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (time_delta == 0)
1979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return 0;
1989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int cpu = GetProcessCPU(process_);
2009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // We have the number of jiffies in the time period.  Convert to percentage.
2029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Note this means we will go *over* 100 in the case where multiple threads
2039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // are together adding to more than one CPU's worth.
2049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu);
2059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_);
2069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int percentage = 100 * (cpu_time - last_cpu_time).InSecondsF() /
2079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      TimeDelta::FromMicroseconds(time_delta).InSecondsF();
2089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  last_cpu_time_ = time;
2109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  last_cpu_ = cpu;
2119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return percentage;
2139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
2149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
2169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// in your kernel configuration.
2179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
2189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Synchronously reading files in /proc is safe.
2199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ThreadRestrictions::ScopedAllowIO allow_io;
2209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string proc_io_contents;
2229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath io_file = internal::GetProcPidDir(process_).Append("io");
2239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ReadFileToString(io_file, &proc_io_contents))
2249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
2259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  (*io_counters).OtherOperationCount = 0;
2279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  (*io_counters).OtherTransferCount = 0;
2289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  StringTokenizer tokenizer(proc_io_contents, ": \n");
2309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ParsingState state = KEY_NAME;
2319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  StringPiece last_key_name;
2329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  while (tokenizer.GetNext()) {
2339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    switch (state) {
2349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      case KEY_NAME:
2359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        last_key_name = tokenizer.token_piece();
2369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        state = KEY_VALUE;
2379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        break;
2389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      case KEY_VALUE:
2399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        DCHECK(!last_key_name.empty());
2409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        if (last_key_name == "syscr") {
2419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          StringToInt64(tokenizer.token_piece(),
2429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall              reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
2439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        } else if (last_key_name == "syscw") {
2449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          StringToInt64(tokenizer.token_piece(),
2459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall              reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
2469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        } else if (last_key_name == "rchar") {
2479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          StringToInt64(tokenizer.token_piece(),
2489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall              reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
2499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        } else if (last_key_name == "wchar") {
2509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          StringToInt64(tokenizer.token_piece(),
2519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall              reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
2529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        }
2539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        state = KEY_NAME;
2549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        break;
2559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
2569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
2579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
2589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
2599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallProcessMetrics::ProcessMetrics(ProcessHandle process)
2619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    : process_(process),
2629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      last_system_time_(0),
2639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      last_cpu_(0) {
2649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  processor_count_ = base::SysInfo::NumberOfProcessors();
2659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
2669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(OS_CHROMEOS)
2689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Private, Shared and Proportional working set sizes are obtained from
2699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// /proc/<pid>/totmaps
2709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage)
2719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  const {
2729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // The format of /proc/<pid>/totmaps is:
2739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  //
2749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Rss:                6120 kB
2759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Pss:                3335 kB
2769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Shared_Clean:       1008 kB
2779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Shared_Dirty:       4012 kB
2789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Private_Clean:         4 kB
2799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Private_Dirty:      1096 kB
2809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Referenced:          XXX kB
2819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Anonymous:           XXX kB
2829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // AnonHugePages:       XXX kB
2839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Swap:                XXX kB
2849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Locked:              XXX kB
2859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  const size_t kPssIndex = (1 * 3) + 1;
2869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  const size_t kPrivate_CleanIndex = (4 * 3) + 1;
2879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  const size_t kPrivate_DirtyIndex = (5 * 3) + 1;
2889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  const size_t kSwapIndex = (9 * 3) + 1;
2899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string totmaps_data;
2919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  {
2929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps");
2939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    ThreadRestrictions::ScopedAllowIO allow_io;
2949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    bool ret = ReadFileToString(totmaps_file, &totmaps_data);
2959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (!ret || totmaps_data.length() == 0)
2969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      return false;
2979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
2989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::vector<std::string> totmaps_fields;
3009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  SplitStringAlongWhitespace(totmaps_data, &totmaps_fields);
3019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]);
3039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]);
3049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex - 1]);
3059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  DCHECK_EQ("Swap:", totmaps_fields[kSwapIndex-1]);
3069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int pss = 0;
3089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int private_clean = 0;
3099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int private_dirty = 0;
3109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int swap = 0;
3119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  bool ret = true;
3129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ret &= StringToInt(totmaps_fields[kPssIndex], &pss);
3139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean);
3149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty);
3159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ret &= StringToInt(totmaps_fields[kSwapIndex], &swap);
3169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // On ChromeOS swap is to zram. We count this as private / shared, as
3189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // increased swap decreases available RAM to user processes, which would
3199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // otherwise create surprising results.
3209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->priv = private_clean + private_dirty + swap;
3219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->shared = pss + swap;
3229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->shareable = 0;
3239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->swapped = swap;
3249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return ret;
3259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
3269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
3279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
3299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage)
3309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    const {
3319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Use statm instead of smaps because smaps is:
3329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // a) Large and slow to parse.
3339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // b) Unavailable in the SUID sandbox.
3349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // First we need to get the page size, since everything is measured in pages.
3369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // For details, see: man 5 proc.
3379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  const int page_size_kb = getpagesize() / 1024;
3389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (page_size_kb <= 0)
3399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
3409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string statm;
3429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  {
3439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    FilePath statm_file = internal::GetProcPidDir(process_).Append("statm");
3449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // Synchronously reading files in /proc is safe.
3459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    ThreadRestrictions::ScopedAllowIO allow_io;
3469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    bool ret = ReadFileToString(statm_file, &statm);
3479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (!ret || statm.length() == 0)
3489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      return false;
3499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
3509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::vector<std::string> statm_vec;
3529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  SplitString(statm, ' ', &statm_vec);
3539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (statm_vec.size() != 7)
3549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;  // Not the format we expect.
3559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int statm_rss, statm_shared;
3579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  bool ret = true;
3589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ret &= StringToInt(statm_vec[1], &statm_rss);
3599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ret &= StringToInt(statm_vec[2], &statm_shared);
3609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->priv = (statm_rss - statm_shared) * page_size_kb;
3629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->shared = statm_shared * page_size_kb;
3639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Sharable is not calculated, as it does not provide interesting data.
3659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->shareable = 0;
3669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(OS_CHROMEOS)
3689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Can't get swapped memory from statm.
3699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ws_usage->swapped = 0;
3709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
3719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return ret;
3739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
3749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsize_t GetSystemCommitCharge() {
3769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  SystemMemoryInfoKB meminfo;
3779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!GetSystemMemoryInfo(&meminfo))
3789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return 0;
3799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
3809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
3819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// Exposed for testing.
3839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallint ParseProcStatCPU(const std::string& input) {
3849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::vector<std::string> proc_stats;
3859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!internal::ParseProcStats(input, &proc_stats))
3869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return -1;
3879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (proc_stats.size() <= internal::VM_STIME)
3899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return -1;
3909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int utime = GetProcStatsFieldAsInt64(proc_stats, internal::VM_UTIME);
3919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  int stime = GetProcStatsFieldAsInt64(proc_stats, internal::VM_STIME);
3929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return utime + stime;
3939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
3949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst char kProcSelfExe[] = "/proc/self/exe";
3969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallint GetNumberOfThreads(ProcessHandle process) {
3989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return internal::ReadProcStatsAndGetFieldAsInt64(process,
3999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                                   internal::VM_NUMTHREADS);
4009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
4019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallnamespace {
4039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// The format of /proc/diskstats is:
4059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Device major number
4069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Device minor number
4079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Device name
4089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  1 -- # of reads completed
4099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This is the total number of reads completed successfully.
4109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  2 -- # of reads merged, field 6 -- # of writes merged
4119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      Reads and writes which are adjacent to each other may be merged for
4129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      efficiency.  Thus two 4K reads may become one 8K read before it is
4139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      ultimately handed to the disk, and so it will be counted (and queued)
4149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      as only one I/O.  This field lets you know how often this was done.
4159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  3 -- # of sectors read
4169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This is the total number of sectors read successfully.
4179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  4 -- # of milliseconds spent reading
4189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This is the total number of milliseconds spent by all reads (as
4199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      measured from __make_request() to end_that_request_last()).
4209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  5 -- # of writes completed
4219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This is the total number of writes completed successfully.
4229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  6 -- # of writes merged
4239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      See the description of field 2.
4249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  7 -- # of sectors written
4259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This is the total number of sectors written successfully.
4269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  8 -- # of milliseconds spent writing
4279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This is the total number of milliseconds spent by all writes (as
4289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      measured from __make_request() to end_that_request_last()).
4299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field  9 -- # of I/Os currently in progress
4309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      The only field that should go to zero. Incremented as requests are
4319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      given to appropriate struct request_queue and decremented as they
4329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      finish.
4339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field 10 -- # of milliseconds spent doing I/Os
4349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This field increases so long as field 9 is nonzero.
4359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//  Field 11 -- weighted # of milliseconds spent doing I/Os
4369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      This field is incremented at each I/O start, I/O completion, I/O
4379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      merge, or read of these stats by the number of I/Os in progress
4389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      (field 9) times the number of milliseconds spent doing I/O since the
4399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      last update of this field.  This can provide an easy measure of both
4409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall//      I/O completion time and the backlog that may be accumulating.
4419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskDriveName = 2;
4439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskReads = 3;
4449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskReadsMerged = 4;
4459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskSectorsRead = 5;
4469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskReadTime = 6;
4479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskWrites = 7;
4489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskWritesMerged = 8;
4499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskSectorsWritten = 9;
4509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskWriteTime = 10;
4519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskIO = 11;
4529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskIOTime = 12;
4539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallconst size_t kDiskWeightedIOTime = 13;
4549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}  // namespace
4569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallSystemMemoryInfoKB::SystemMemoryInfoKB() {
4589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  total = 0;
4599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  free = 0;
4609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  buffers = 0;
4619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  cached = 0;
4629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  active_anon = 0;
4639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  inactive_anon = 0;
4649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  active_file = 0;
4659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  inactive_file = 0;
4669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_total = 0;
4679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_free = 0;
4689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  dirty = 0;
4699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  pswpin = 0;
4719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  pswpout = 0;
4729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  pgmajfault = 0;
4739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef OS_CHROMEOS
4759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  shmem = 0;
4769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  slab = 0;
4779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  gem_objects = -1;
4789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  gem_size = -1;
4799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
4809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
4819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallscoped_ptr<Value> SystemMemoryInfoKB::ToValue() const {
4839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  scoped_ptr<DictionaryValue> res(new base::DictionaryValue());
4849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("total", total);
4869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("free", free);
4879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("buffers", buffers);
4889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("cached", cached);
4899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("active_anon", active_anon);
4909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("inactive_anon", inactive_anon);
4919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("active_file", active_file);
4929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("inactive_file", inactive_file);
4939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("swap_total", swap_total);
4949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("swap_free", swap_free);
4959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("swap_used", swap_total - swap_free);
4969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("dirty", dirty);
4979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("pswpin", pswpin);
4989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("pswpout", pswpout);
4999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("pgmajfault", pgmajfault);
5009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef OS_CHROMEOS
5019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("shmem", shmem);
5029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("slab", slab);
5039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("gem_objects", gem_objects);
5049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetInteger("gem_size", gem_size);
5059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
5069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return res.PassAs<Value>();
5089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
5099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// exposed for testing
5119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ParseProcMeminfo(const std::string& meminfo_data,
5129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                      SystemMemoryInfoKB* meminfo) {
5139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // The format of /proc/meminfo is:
5149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  //
5159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // MemTotal:      8235324 kB
5169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // MemFree:       1628304 kB
5179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Buffers:        429596 kB
5189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Cached:        4728232 kB
5199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // ...
5209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // There is no guarantee on the ordering or position
5219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // though it doesn't appear to change very often
5229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // As a basic sanity check, let's make sure we at least get non-zero
5249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // MemTotal value
5259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  meminfo->total = 0;
5269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::vector<std::string> meminfo_lines;
5289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  Tokenize(meminfo_data, "\n", &meminfo_lines);
5299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  for (std::vector<std::string>::iterator it = meminfo_lines.begin();
5309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall       it != meminfo_lines.end(); ++it) {
5319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    std::vector<std::string> tokens;
5329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    SplitStringAlongWhitespace(*it, &tokens);
5339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // HugePages_* only has a number and no suffix so we can't rely on
5349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // there being exactly 3 tokens.
5359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (tokens.size() > 1) {
5369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      if (tokens[0] == "MemTotal:") {
5379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->total);
5389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "MemFree:") {
5409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->free);
5419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Buffers:") {
5439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->buffers);
5449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Cached:") {
5469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->cached);
5479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Active(anon):") {
5499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->active_anon);
5509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Inactive(anon):") {
5529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->inactive_anon);
5539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Active(file):") {
5559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->active_file);
5569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Inactive(file):") {
5589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->inactive_file);
5599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "SwapTotal:") {
5619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->swap_total);
5629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "SwapFree:") {
5649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->swap_free);
5659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Dirty:") {
5679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->dirty);
5689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(OS_CHROMEOS)
5709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      // Chrome OS has a tweaked kernel that allows us to query Shmem, which is
5719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      // usually video memory otherwise invisible to the OS.
5729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Shmem:") {
5739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->shmem);
5749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "Slab:") {
5769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->slab);
5779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
5789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
5799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      }
5809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    } else
5819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
5829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                    << " malformed line: " << *it;
5839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
5849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Make sure we got a valid MemTotal.
5869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!meminfo->total)
5879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
5889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
5909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
5919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall// exposed for testing
5939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool ParseProcVmstat(const std::string& vmstat_data,
5949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                     SystemMemoryInfoKB* meminfo) {
5959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // The format of /proc/vmstat is:
5969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  //
5979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // nr_free_pages 299878
5989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // nr_inactive_anon 239863
5999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // nr_active_anon 1318966
6009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // nr_inactive_file 2015629
6019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // ...
6029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  //
6039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // We iterate through the whole file because the position of the
6049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // fields are dependent on the kernel version and configuration.
6059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::vector<std::string> vmstat_lines;
6079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  Tokenize(vmstat_data, "\n", &vmstat_lines);
6089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  for (std::vector<std::string>::iterator it = vmstat_lines.begin();
6099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall       it != vmstat_lines.end(); ++it) {
6109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    std::vector<std::string> tokens;
6119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    SplitString(*it, ' ', &tokens);
6129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (tokens.size() == 2) {
6139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      if (tokens[0] == "pswpin") {
6149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->pswpin);
6159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
6169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "pswpout") {
6179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->pswpout);
6189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        continue;
6199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      } if (tokens[0] == "pgmajfault")
6209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        StringToInt(tokens[1], &meminfo->pgmajfault);
6219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
6229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
6259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
6269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
6289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Synchronously reading files in /proc is safe.
6299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ThreadRestrictions::ScopedAllowIO allow_io;
6309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Used memory is: total - free - buffers - caches
6329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath meminfo_file("/proc/meminfo");
6339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string meminfo_data;
6349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ReadFileToString(meminfo_file, &meminfo_data)) {
6359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DLOG(WARNING) << "Failed to open " << meminfo_file.value();
6369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
6379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ParseProcMeminfo(meminfo_data, meminfo)) {
6409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DLOG(WARNING) << "Failed to parse " << meminfo_file.value();
6419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
6429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(OS_CHROMEOS)
6459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Report on Chrome OS GEM object graphics memory. /var/run/debugfs_gpu is a
6469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // bind mount into /sys/kernel/debug and synchronously reading the in-memory
6479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // files in /sys is fast.
6489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(ARCH_CPU_ARM_FAMILY)
6499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath geminfo_file("/var/run/debugfs_gpu/exynos_gem_objects");
6509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#else
6519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath geminfo_file("/var/run/debugfs_gpu/i915_gem_objects");
6529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
6539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string geminfo_data;
6549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  meminfo->gem_objects = -1;
6559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  meminfo->gem_size = -1;
6569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (ReadFileToString(geminfo_file, &geminfo_data)) {
6579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    int gem_objects = -1;
6589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    long long gem_size = -1;
6599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    int num_res = sscanf(geminfo_data.c_str(),
6609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                         "%d objects, %lld bytes",
6619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                         &gem_objects, &gem_size);
6629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (num_res == 2) {
6639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      meminfo->gem_objects = gem_objects;
6649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      meminfo->gem_size = gem_size;
6659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
6669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(ARCH_CPU_ARM_FAMILY)
6699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Incorporate Mali graphics memory if present.
6709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath mali_memory_file("/sys/class/misc/mali0/device/memory");
6719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string mali_memory_data;
6729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (ReadFileToString(mali_memory_file, &mali_memory_data)) {
6739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    long long mali_size = -1;
6749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    int num_res = sscanf(mali_memory_data.c_str(), "%lld bytes", &mali_size);
6759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (num_res == 1)
6769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      meminfo->gem_size += mali_size;
6779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif  // defined(ARCH_CPU_ARM_FAMILY)
6799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif  // defined(OS_CHROMEOS)
6809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath vmstat_file("/proc/vmstat");
6829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string vmstat_data;
6839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ReadFileToString(vmstat_file, &vmstat_data)) {
6849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DLOG(WARNING) << "Failed to open " << vmstat_file.value();
6859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
6869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ParseProcVmstat(vmstat_data, meminfo)) {
6889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DLOG(WARNING) << "Failed to parse " << vmstat_file.value();
6899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
6909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
6919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
6939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
6949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallSystemDiskInfo::SystemDiskInfo() {
6969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  reads = 0;
6979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  reads_merged = 0;
6989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  sectors_read = 0;
6999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  read_time = 0;
7009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  writes = 0;
7019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  writes_merged = 0;
7029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  sectors_written = 0;
7039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  write_time = 0;
7049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  io = 0;
7059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  io_time = 0;
7069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  weighted_io_time = 0;
7079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
7089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallscoped_ptr<Value> SystemDiskInfo::ToValue() const {
7109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  scoped_ptr<DictionaryValue> res(new base::DictionaryValue());
7119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Write out uint64 variables as doubles.
7139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Note: this may discard some precision, but for JS there's no other option.
7149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("reads", static_cast<double>(reads));
7159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("reads_merged", static_cast<double>(reads_merged));
7169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("sectors_read", static_cast<double>(sectors_read));
7179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("read_time", static_cast<double>(read_time));
7189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("writes", static_cast<double>(writes));
7199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("writes_merged", static_cast<double>(writes_merged));
7209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("sectors_written", static_cast<double>(sectors_written));
7219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("write_time", static_cast<double>(write_time));
7229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("io", static_cast<double>(io));
7239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("io_time", static_cast<double>(io_time));
7249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
7259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return res.PassAs<Value>();
7279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
7289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool IsValidDiskName(const std::string& candidate) {
7309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (candidate.length() < 3)
7319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
7329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (candidate.substr(0,2) == "sd" || candidate.substr(0,2) == "hd") {
7339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // [sh]d[a-z]+ case
7349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    for (size_t i = 2; i < candidate.length(); i++) {
7359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      if (!islower(candidate[i]))
7369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        return false;
7379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
7389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  } else {
7399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (candidate.length() < 7) {
7409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      return false;
7419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
7429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (candidate.substr(0,6) == "mmcblk") {
7439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      // mmcblk[0-9]+ case
7449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      for (size_t i = 6; i < candidate.length(); i++) {
7459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        if (!isdigit(candidate[i]))
7469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall          return false;
7479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      }
7489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    } else {
7499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      return false;
7509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
7519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
7529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
7549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
7559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallbool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
7579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Synchronously reading files in /proc is safe.
7589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ThreadRestrictions::ScopedAllowIO allow_io;
7599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  FilePath diskinfo_file("/proc/diskstats");
7619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::string diskinfo_data;
7629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (!ReadFileToString(diskinfo_file, &diskinfo_data)) {
7639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DLOG(WARNING) << "Failed to open " << diskinfo_file.value();
7649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
7659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
7669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  std::vector<std::string> diskinfo_lines;
7689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  size_t line_count = Tokenize(diskinfo_data, "\n", &diskinfo_lines);
7699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (line_count == 0) {
7709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    DLOG(WARNING) << "No lines found";
7719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return false;
7729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
7739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->reads = 0;
7759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->reads_merged = 0;
7769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->sectors_read = 0;
7779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->read_time = 0;
7789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->writes = 0;
7799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->writes_merged = 0;
7809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->sectors_written = 0;
7819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->write_time = 0;
7829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->io = 0;
7839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->io_time = 0;
7849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  diskinfo->weighted_io_time = 0;
7859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 reads = 0;
7879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 reads_merged = 0;
7889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 sectors_read = 0;
7899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 read_time = 0;
7909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 writes = 0;
7919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 writes_merged = 0;
7929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 sectors_written = 0;
7939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 write_time = 0;
7949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 io = 0;
7959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 io_time = 0;
7969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 weighted_io_time = 0;
7979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  for (size_t i = 0; i < line_count; i++) {
7999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    std::vector<std::string> disk_fields;
8009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    SplitStringAlongWhitespace(diskinfo_lines[i], &disk_fields);
8019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // Fields may have overflowed and reset to zero.
8039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if (IsValidDiskName(disk_fields[kDiskDriveName])) {
8049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskReads], &reads);
8059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
8069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
8079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskReadTime], &read_time);
8089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskWrites], &writes);
8099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskWritesMerged], &writes_merged);
8109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskSectorsWritten], &sectors_written);
8119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskWriteTime], &write_time);
8129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskIO], &io);
8139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskIOTime], &io_time);
8149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      StringToUint64(disk_fields[kDiskWeightedIOTime], &weighted_io_time);
8159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->reads += reads;
8179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->reads_merged += reads_merged;
8189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->sectors_read += sectors_read;
8199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->read_time += read_time;
8209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->writes += writes;
8219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->writes_merged += writes_merged;
8229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->sectors_written += sectors_written;
8239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->write_time += write_time;
8249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->io += io;
8259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->io_time += io_time;
8269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      diskinfo->weighted_io_time += weighted_io_time;
8279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
8289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
8299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return true;
8319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(OS_CHROMEOS)
8349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallscoped_ptr<Value> SwapInfo::ToValue() const {
8359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  scoped_ptr<DictionaryValue> res(new DictionaryValue());
8369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Write out uint64 variables as doubles.
8389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Note: this may discard some precision, but for JS there's no other option.
8399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("num_reads", static_cast<double>(num_reads));
8409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("num_writes", static_cast<double>(num_writes));
8419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("orig_data_size", static_cast<double>(orig_data_size));
8429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("compr_data_size", static_cast<double>(compr_data_size));
8439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  res->SetDouble("mem_used_total", static_cast<double>(mem_used_total));
8449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (compr_data_size > 0)
8459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    res->SetDouble("compression_ratio", static_cast<double>(orig_data_size) /
8469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                        static_cast<double>(compr_data_size));
8479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  else
8489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    res->SetDouble("compression_ratio", 0);
8499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  return res.PassAs<Value>();
8519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid GetSwapInfo(SwapInfo* swap_info) {
8549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  // Synchronously reading files in /sys/block/zram0 is safe.
8559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  ThreadRestrictions::ScopedAllowIO allow_io;
8569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  base::FilePath zram_path("/sys/block/zram0");
8589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size"));
8599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  if (orig_data_size <= 4096) {
8609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // A single page is compressed at startup, and has a high compression
8619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    // ratio. We ignore this as it doesn't indicate any real swapping.
8629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    swap_info->orig_data_size = 0;
8639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    swap_info->num_reads = 0;
8649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    swap_info->num_writes = 0;
8659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    swap_info->compr_data_size = 0;
8669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    swap_info->mem_used_total = 0;
8679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    return;
8689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  }
8699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_info->orig_data_size = orig_data_size;
8709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads"));
8719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes"));
8729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_info->compr_data_size =
8739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      ReadFileToUint64(zram_path.Append("compr_data_size"));
8749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  swap_info->mem_used_total =
8759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall      ReadFileToUint64(zram_path.Append("mem_used_total"));
8769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif  // defined(OS_CHROMEOS)
8789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}  // namespace base
8809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall