blob: 85adb19bcb6454733ab807180a485440374997e6 [file] [log] [blame]
[email protected]f164cea2009-11-05 23:37:401// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/process_info_snapshot.h"
6
[email protected]f164cea2009-11-05 23:37:407#include <sstream>
8
[email protected]5d91c9e2010-07-28 17:25:289#include "base/command_line.h"
[email protected]983ef7f2010-01-04 16:17:1310#include "base/logging.h"
[email protected]528c56d2010-07-30 19:28:4411#include "base/string_number_conversions.h"
[email protected]f164cea2009-11-05 23:37:4012#include "base/string_util.h"
[email protected]34b99632011-01-01 01:01:0613#include "base/threading/thread.h"
[email protected]f164cea2009-11-05 23:37:4014
15// Implementation for the Mac; calls '/bin/ps' for information when
16// |Sample()| is called.
17
18// Default constructor.
19ProcessInfoSnapshot::ProcessInfoSnapshot() { }
20
21// Destructor: just call |Reset()| to release everything.
22ProcessInfoSnapshot::~ProcessInfoSnapshot() {
23 Reset();
24}
25
[email protected]983ef7f2010-01-04 16:17:1326const size_t ProcessInfoSnapshot::kMaxPidListSize = 1000;
27
[email protected]f164cea2009-11-05 23:37:4028// Capture the information by calling '/bin/ps'.
29// Note: we ignore the "tsiz" (text size) display option of ps because it's
30// always zero (tested on 10.5 and 10.6).
31bool ProcessInfoSnapshot::Sample(std::vector<base::ProcessId> pid_list) {
[email protected]3de98b32009-11-21 02:53:0832 const char* kPsPathName = "/bin/ps";
[email protected]f164cea2009-11-05 23:37:4033 Reset();
34
[email protected]983ef7f2010-01-04 16:17:1335 // Nothing to do if no PIDs given.
36 if (pid_list.size() == 0)
37 return true;
38 if (pid_list.size() > kMaxPidListSize) {
39 // The spec says |pid_list| *must* not have more than this many entries.
40 NOTREACHED();
41 return false;
42 }
43
[email protected]f164cea2009-11-05 23:37:4044 std::vector<std::string> argv;
[email protected]3de98b32009-11-21 02:53:0845 argv.push_back(kPsPathName);
[email protected]f164cea2009-11-05 23:37:4046 // Get PID, PPID, (real) UID, effective UID, resident set size, virtual memory
47 // size, and command.
48 argv.push_back("-o");
49 argv.push_back("pid=,ppid=,ruid=,uid=,rss=,vsz=,comm=");
50 // Only display the specified PIDs.
[email protected]4a3dab22009-11-11 17:36:5051 for (std::vector<base::ProcessId>::iterator it = pid_list.begin();
[email protected]f164cea2009-11-05 23:37:4052 it != pid_list.end(); ++it) {
53 argv.push_back("-p");
[email protected]528c56d2010-07-30 19:28:4454 argv.push_back(base::Int64ToString(static_cast<int64>(*it)));
[email protected]f164cea2009-11-05 23:37:4055 }
56
57 std::string output;
58 CommandLine command_line(argv);
[email protected]983ef7f2010-01-04 16:17:1359 // Limit output read to a megabyte for safety.
60 if (!base::GetAppOutputRestricted(command_line, &output, 1024 * 1024)) {
[email protected]3de98b32009-11-21 02:53:0861 LOG(ERROR) << "Failure running " << kPsPathName << " to acquire data.";
[email protected]f164cea2009-11-05 23:37:4062 return false;
63 }
64
65 std::istringstream in(output, std::istringstream::in);
66 std::string line;
67
68 // Process lines until done.
69 while (true) {
70 ProcInfoEntry proc_info;
71
72 // The format is as specified above to ps (see ps(1)):
73 // "-o pid=,ppid=,ruid=,uid=,rss=,vsz=,comm=".
74 // Try to read the PID; if we get it, we should be able to get the rest of
75 // the line.
76 in >> proc_info.pid;
77 if (in.eof())
78 break;
79 in >> proc_info.ppid;
80 in >> proc_info.uid;
81 in >> proc_info.euid;
82 in >> proc_info.rss;
83 in >> proc_info.vsize;
84 in.ignore(1, ' '); // Eat the space.
85 std::getline(in, proc_info.command); // Get the rest of the line.
86 if (!in.good()) {
[email protected]3de98b32009-11-21 02:53:0887 LOG(ERROR) << "Error parsing output from " << kPsPathName << ".";
[email protected]f164cea2009-11-05 23:37:4088 return false;
89 }
90
91 // Make sure the new PID isn't already in our list.
92 if (proc_info_entries_.find(proc_info.pid) != proc_info_entries_.end()) {
[email protected]3de98b32009-11-21 02:53:0893 LOG(ERROR) << "Duplicate PID in output from " << kPsPathName << ".";
[email protected]f164cea2009-11-05 23:37:4094 return false;
95 }
96
97 if (!proc_info.pid || ! proc_info.vsize) {
[email protected]3de98b32009-11-21 02:53:0898 LOG(WARNING) << "Invalid data from " << kPsPathName << ".";
[email protected]f164cea2009-11-05 23:37:4099 return false;
100 }
101
102 // Record the process information.
103 proc_info_entries_[proc_info.pid] = proc_info;
104 }
105
106 return true;
107}
108
109// Clear all the stored information.
110void ProcessInfoSnapshot::Reset() {
111 proc_info_entries_.clear();
112}
113
114bool ProcessInfoSnapshot::GetProcInfo(int pid,
115 ProcInfoEntry* proc_info) const {
116 std::map<int,ProcInfoEntry>::const_iterator it = proc_info_entries_.find(pid);
117 if (it == proc_info_entries_.end())
118 return false;
119
120 *proc_info = it->second;
121 return true;
122}
123
124bool ProcessInfoSnapshot::GetCommittedKBytesOfPID(
125 int pid,
126 base::CommittedKBytes* usage) const {
127 // Try to avoid crashing on a bug; stats aren't usually so crucial.
128 if (!usage) {
129 NOTREACHED();
130 return false;
131 }
132
133 // Failure of |GetProcInfo()| is "normal", due to racing.
134 ProcInfoEntry proc_info;
135 if (!GetProcInfo(pid, &proc_info)) {
136 usage->priv = 0;
137 usage->mapped = 0;
138 usage->image = 0;
139 return false;
140 }
141
142 usage->priv = proc_info.vsize;
143 usage->mapped = 0;
144 usage->image = 0;
145 return true;
146}
147
148bool ProcessInfoSnapshot::GetWorkingSetKBytesOfPID(
149 int pid,
150 base::WorkingSetKBytes* ws_usage) const {
151 // Try to avoid crashing on a bug; stats aren't usually so crucial.
152 if (!ws_usage) {
153 NOTREACHED();
154 return false;
155 }
156
157 // Failure of |GetProcInfo()| is "normal", due to racing.
158 ProcInfoEntry proc_info;
159 if (!GetProcInfo(pid, &proc_info)) {
160 ws_usage->priv = 0;
161 ws_usage->shareable = 0;
162 ws_usage->shared = 0;
163 return false;
164 }
165
166 ws_usage->priv = 0;
167 ws_usage->shareable = proc_info.rss;
168 ws_usage->shared = 0;
169 return true;
170}