Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: base/process_util_linux.cc

Issue 365007: Linux: use /proc/pid/statm to get memory stats when /proc/pid/smaps is unavai... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/browser/resources/about_memory_linux.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/process_util.h" 5 #include "base/process_util.h"
6 6
7 #include <ctype.h> 7 #include <ctype.h>
8 #include <dirent.h> 8 #include <dirent.h>
9 #include <errno.h> 9 #include <errno.h>
10 #include <fcntl.h> 10 #include <fcntl.h>
11 #include <sys/time.h> 11 #include <sys/time.h>
12 #include <sys/types.h> 12 #include <sys/types.h>
13 #include <sys/wait.h> 13 #include <sys/wait.h>
14 #include <time.h> 14 #include <time.h>
15 #include <unistd.h> 15 #include <unistd.h>
16 16
17 #include <string>
18
19 #include "base/file_util.h" 17 #include "base/file_util.h"
20 #include "base/logging.h" 18 #include "base/logging.h"
21 #include "base/string_tokenizer.h" 19 #include "base/string_tokenizer.h"
22 #include "base/string_util.h" 20 #include "base/string_util.h"
23 21
24 namespace { 22 namespace {
25 23
26 enum ParsingState { 24 enum ParsingState {
27 KEY_NAME, 25 KEY_NAME,
28 KEY_VALUE 26 KEY_VALUE
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 } 244 }
247 return 0; 245 return 0;
248 } 246 }
249 247
250 size_t ProcessMetrics::GetPrivateBytes() const { 248 size_t ProcessMetrics::GetPrivateBytes() const {
251 WorkingSetKBytes ws_usage; 249 WorkingSetKBytes ws_usage;
252 GetWorkingSetKBytes(&ws_usage); 250 GetWorkingSetKBytes(&ws_usage);
253 return ws_usage.priv << 10; 251 return ws_usage.priv << 10;
254 } 252 }
255 253
256 // Private and Shared working set sizes are obtained from /proc/<pid>/smaps, 254 // Private and Shared working set sizes are obtained from /proc/<pid>/smaps.
257 // as in http://www.pixelbeat.org/scripts/ps_mem.py 255 // When that's not available, use the values from /proc<pid>/statm as a
256 // close approximation.
257 // See http://www.pixelbeat.org/scripts/ps_mem.py
258 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { 258 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
259 FilePath stat_file = 259 FilePath stat_file =
260 FilePath("/proc").Append(IntToString(process_)).Append("smaps"); 260 FilePath("/proc").Append(IntToString(process_)).Append("smaps");
261 std::string smaps; 261 std::string smaps;
262 int private_kb = 0; 262 int private_kb = 0;
263 int pss_kb = 0; 263 int pss_kb = 0;
264 bool have_pss = false; 264 bool have_pss = false;
265 if (!file_util::ReadFileToString(stat_file, &smaps) || smaps.length() == 0) 265 if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) {
266 return false; 266 StringTokenizer tokenizer(smaps, ":\n");
267 ParsingState state = KEY_NAME;
268 std::string last_key_name;
269 while (tokenizer.GetNext()) {
270 switch (state) {
271 case KEY_NAME:
272 last_key_name = tokenizer.token();
273 state = KEY_VALUE;
274 break;
275 case KEY_VALUE:
276 if (last_key_name.empty()) {
277 NOTREACHED();
278 return false;
279 }
280 if (StartsWithASCII(last_key_name, "Private_", 1)) {
281 private_kb += StringToInt(tokenizer.token());
282 } else if (StartsWithASCII(last_key_name, "Pss", 1)) {
283 have_pss = true;
284 pss_kb += StringToInt(tokenizer.token());
285 }
286 state = KEY_NAME;
287 break;
288 }
289 }
290 } else {
291 // Try statm if smaps is empty because of the SUID sandbox.
292 // First we need to get the page size though.
293 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
294 if (page_size_kb <= 0)
295 return false;
267 296
268 StringTokenizer tokenizer(smaps, ":\n"); 297 stat_file =
269 ParsingState state = KEY_NAME; 298 FilePath("/proc").Append(IntToString(process_)).Append("statm");
270 std::string last_key_name; 299 std::string statm;
271 while (tokenizer.GetNext()) { 300 if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0)
272 switch (state) { 301 return false;
273 case KEY_NAME: 302
274 last_key_name = tokenizer.token(); 303 std::vector<std::string> statm_vec;
275 state = KEY_VALUE; 304 SplitString(statm, ' ', &statm_vec);
276 break; 305 if (statm_vec.size() != 7)
277 case KEY_VALUE: 306 return false; // Not the format we expect.
278 if (last_key_name.empty()) { 307 private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]);
279 NOTREACHED(); 308 private_kb *= page_size_kb;
280 return false;
281 }
282 if (StartsWithASCII(last_key_name, "Private_", 1)) {
283 private_kb += StringToInt(tokenizer.token());
284 } else if (StartsWithASCII(last_key_name, "Pss", 1)) {
285 have_pss = true;
286 pss_kb += StringToInt(tokenizer.token());
287 }
288 state = KEY_NAME;
289 break;
290 }
291 } 309 }
292 ws_usage->priv = private_kb; 310 ws_usage->priv = private_kb;
293 // Sharable is not calculated, as it does not provide interesting data. 311 // Sharable is not calculated, as it does not provide interesting data.
294 ws_usage->shareable = 0; 312 ws_usage->shareable = 0;
295 313
296 ws_usage->shared = 0; 314 ws_usage->shared = 0;
297 if (have_pss) 315 if (have_pss)
298 ws_usage->shared = pss_kb; 316 ws_usage->shared = pss_kb;
299 return true; 317 return true;
300 } 318 }
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 int64 time = TimeValToMicroseconds(now); 425 int64 time = TimeValToMicroseconds(now);
408 426
409 if (last_time_ == 0) { 427 if (last_time_ == 0) {
410 // First call, just set the last values. 428 // First call, just set the last values.
411 last_time_ = time; 429 last_time_ = time;
412 last_cpu_ = GetProcessCPU(process_); 430 last_cpu_ = GetProcessCPU(process_);
413 return 0; 431 return 0;
414 } 432 }
415 433
416 int64 time_delta = time - last_time_; 434 int64 time_delta = time - last_time_;
417 DCHECK(time_delta != 0); 435 DCHECK_NE(time_delta, 0);
418 if (time_delta == 0) 436 if (time_delta == 0)
419 return 0; 437 return 0;
420 438
421 int cpu = GetProcessCPU(process_); 439 int cpu = GetProcessCPU(process_);
422 440
423 // We have the number of jiffies in the time period. Convert to percentage. 441 // We have the number of jiffies in the time period. Convert to percentage.
424 // Note this means we will go *over* 100 in the case where multiple threads 442 // Note this means we will go *over* 100 in the case where multiple threads
425 // are together adding to more than one CPU's worth. 443 // are together adding to more than one CPU's worth.
426 int percentage = 100 * (cpu - last_cpu_) / 444 int percentage = 100 * (cpu - last_cpu_) /
427 (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF()); 445 (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF());
428 446
429 last_time_ = time; 447 last_time_ = time;
430 last_cpu_ = cpu; 448 last_cpu_ = cpu;
431 449
432 return percentage; 450 return percentage;
433 } 451 }
434 452
435 } // namespace base 453 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/about_memory_linux.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698