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