15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/process_info_snapshot.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/sysctl.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sstream>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
12bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/files/file_path.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
14bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default constructor.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessInfoSnapshot::ProcessInfoSnapshot() { }
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Destructor: just call |Reset()| to release everything.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessInfoSnapshot::~ProcessInfoSnapshot() {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reset();
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t ProcessInfoSnapshot::kMaxPidListSize = 1000;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool GetKInfoForProcessID(pid_t pid, kinfo_proc* kinfo) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t len = sizeof(*kinfo);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sysctl(mib, arraysize(mib), kinfo, &len, NULL, 0) != 0) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(ERROR) << "sysctl() for KERN_PROC";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len == 0) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the process isn't found then sysctl returns a length of 0.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool GetExecutableNameForProcessID(
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pid_t pid,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* executable_name) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!executable_name) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int s_arg_max = 0;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (s_arg_max == 0) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int mib[] = {CTL_KERN, KERN_ARGMAX};
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t size = sizeof(s_arg_max);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (sysctl(mib, arraysize(mib), &s_arg_max, &size, NULL, 0) != 0)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(ERROR) << "sysctl() for KERN_ARGMAX";
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (s_arg_max == 0)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mib[] = {CTL_KERN, KERN_PROCARGS, pid};
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = s_arg_max;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  executable_name->resize(s_arg_max + 1);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sysctl(mib, arraysize(mib), &(*executable_name)[0],
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             &size, NULL, 0) != 0) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't log the error since it's normal for this to fail.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // KERN_PROCARGS returns multiple NULL terminated strings. Truncate
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // executable_name to just the first string.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t end_pos = executable_name->find('\0');
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (end_pos == std::string::npos) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  executable_name->resize(end_pos);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts a byte unit such as 'K' or 'M' into the scale for the unit.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The scale can then be used to calculate the number of bytes in a value.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The units are based on humanize_number(). See:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.opensource.apple.com/source/libutil/libutil-21/humanize_number.c
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool ConvertByteUnitToScale(char unit, uint64_t* out_scale) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shift = 0;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (unit) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'B':
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 0;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'K':
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'k':
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 1;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'M':
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 2;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'G':
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 3;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'T':
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 4;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'P':
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 5;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'E':
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shift = 6;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64_t scale = 1;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < shift; i++)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scale *= 1024;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *out_scale = scale;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Capture the information by calling '/bin/ps'.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: we ignore the "tsiz" (text size) display option of ps because it's
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// always zero (tested on 10.5 and 10.6).
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool GetProcessMemoryInfoUsingPS(
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<base::ProcessId>& pid_list,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::map<int,ProcessInfoSnapshot::ProcInfoEntry>& proc_info_entries) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath kProgram("/bin/ps");
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(kProgram);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get resident set size, virtual memory size.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("-o");
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("pid=,rss=,vsz=");
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only display the specified PIDs.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<base::ProcessId>::const_iterator it = pid_list.begin();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != pid_list.end(); ++it) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_line.AppendArg("-p");
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_line.AppendArg(base::Int64ToString(static_cast<int64>(*it)));
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit output read to a megabyte for safety.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::GetAppOutputRestricted(command_line, &output, 1024 * 1024)) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failure running " << kProgram.value() << " to acquire data.";
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::istringstream in(output, std::istringstream::in);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Process lines until done.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The format is as specified above to ps (see ps(1)):
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   "-o pid=,rss=,vsz=".
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try to read the PID; if we get it, we should be able to get the rest of
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the line.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pid_t pid;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in >> pid;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (in.eof())
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessInfoSnapshot::ProcInfoEntry proc_info = proc_info_entries[pid];
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.pid = pid;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in >> proc_info.rss;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in >> proc_info.vsize;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.rss *= 1024;                // Convert from kilobytes to bytes.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.vsize *= 1024;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in.ignore(1, ' ');                    // Eat the space.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::getline(in, proc_info.command);  // Get the rest of the line.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!in.good()) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Error parsing output from " << kProgram.value() << ".";
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!proc_info.pid || ! proc_info.vsize) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Invalid data from " << kProgram.value() << ".";
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Record the process information.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info_entries[proc_info.pid] = proc_info;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool GetProcessMemoryInfoUsingTop(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::map<int,ProcessInfoSnapshot::ProcInfoEntry>& proc_info_entries) {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath kProgram("/usr/bin/top");
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(kProgram);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // -stats tells top to print just the given fields as ordered.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("-stats");
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("pid,"    // Process ID
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         "rsize,"  // Resident memory
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         "rshrd,"  // Resident shared memory
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         "rprvt,"  // Resident private memory
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         "vsize"); // Total virtual memory
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run top in logging (non-interactive) mode.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("-l");
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("1");
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the delay between updates to 0.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("-s");
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("0");
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limit output read to a megabyte for safety.
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::GetAppOutputRestricted(command_line, &output, 1024 * 1024)) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failure running " << kProgram.value() << " to acquire data.";
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Process lines until done. Lines should look something like this:
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PID    RSIZE  RSHRD  RPRVT  VSIZE
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 58539  1276K+ 336K+  740K+  2378M+
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 58485  1888K+ 592K+  1332K+ 2383M+
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::istringstream top_in(output, std::istringstream::in);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string line;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (std::getline(top_in, line)) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::istringstream in(line, std::istringstream::in);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try to read the PID.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pid_t pid;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in >> pid;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (in.fail())
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure that caller is interested in this process.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (proc_info_entries.find(pid) == proc_info_entries.end())
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip the - or + sign that top puts after the pid.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in.get();
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64_t values[4];
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t i;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = 0; i < arraysize(values); i++) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in >> values[i];
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (in.fail())
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string unit;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in >> unit;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (in.fail())
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (unit.empty())
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint64_t scale;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!ConvertByteUnitToScale(unit[0], &scale))
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values[i] *= scale;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i != arraysize(values))
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessInfoSnapshot::ProcInfoEntry proc_info = proc_info_entries[pid];
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.rss = values[0];
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.rshrd = values[1];
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.rprvt = values[2];
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.vsize = values[3];
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Record the process information.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info_entries[proc_info.pid] = proc_info;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessInfoSnapshot::Sample(std::vector<base::ProcessId> pid_list) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reset();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nothing to do if no PIDs given.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pid_list.empty())
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pid_list.size() > kMaxPidListSize) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The spec says |pid_list| *must* not have more than this many entries.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get basic process info from KERN_PROC.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<base::ProcessId>::iterator it = pid_list.begin();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != pid_list.end(); ++it) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcInfoEntry proc_info;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.pid = *it;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kinfo_proc kinfo;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetKInfoForProcessID(*it, &kinfo))
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.ppid = kinfo.kp_eproc.e_ppid;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.uid = kinfo.kp_eproc.e_pcred.p_ruid;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.euid = kinfo.kp_eproc.e_ucred.cr_uid;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note, p_comm is truncated to 16 characters.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info.command = kinfo.kp_proc.p_comm;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_info_entries_[*it] = proc_info;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use KERN_PROCARGS to get the full executable name. This may fail if this
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // process doesn't have privileges to inspect the target process.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<base::ProcessId>::iterator it = pid_list.begin();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != pid_list.end(); ++it) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string exectuable_name;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetExecutableNameForProcessID(*it, &exectuable_name)) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProcInfoEntry proc_info = proc_info_entries_[*it];
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc_info.command = exectuable_name;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get memory information using top.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool memory_info_success = GetProcessMemoryInfoUsingTop(proc_info_entries_);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If top didn't work then fall back to ps.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!memory_info_success) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memory_info_success = GetProcessMemoryInfoUsingPS(pid_list,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      proc_info_entries_);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return memory_info_success;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Clear all the stored information.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessInfoSnapshot::Reset() {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proc_info_entries_.clear();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessInfoSnapshot::ProcInfoEntry::ProcInfoEntry()
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : pid(0),
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ppid(0),
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uid(0),
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      euid(0),
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rss(0),
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rshrd(0),
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rprvt(0),
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      vsize(0) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessInfoSnapshot::GetProcInfo(int pid,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      ProcInfoEntry* proc_info) const {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<int,ProcInfoEntry>::const_iterator it = proc_info_entries_.find(pid);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == proc_info_entries_.end())
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *proc_info = it->second;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessInfoSnapshot::GetCommittedKBytesOfPID(
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int pid,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::CommittedKBytes* usage) const {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to avoid crashing on a bug; stats aren't usually so crucial.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usage) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Failure of |GetProcInfo()| is "normal", due to racing.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcInfoEntry proc_info;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetProcInfo(pid, &proc_info)) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usage->priv = 0;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usage->mapped = 0;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usage->image = 0;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage->priv = proc_info.vsize / 1024;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage->mapped = 0;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage->image = 0;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessInfoSnapshot::GetWorkingSetKBytesOfPID(
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int pid,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WorkingSetKBytes* ws_usage) const {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to avoid crashing on a bug; stats aren't usually so crucial.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ws_usage) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Failure of |GetProcInfo()| is "normal", due to racing.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcInfoEntry proc_info;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetProcInfo(pid, &proc_info)) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ws_usage->priv = 0;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ws_usage->shareable = 0;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ws_usage->shared = 0;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ws_usage->priv = proc_info.rprvt / 1024;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ws_usage->shareable = proc_info.rss / 1024;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ws_usage->shared = proc_info.rshrd / 1024;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
397