OLD | NEW |
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 <dlfcn.h> | 9 #include <dlfcn.h> |
10 #include <errno.h> | 10 #include <errno.h> |
11 #include <fcntl.h> | 11 #include <fcntl.h> |
12 #include <sys/time.h> | 12 #include <sys/time.h> |
13 #include <sys/types.h> | 13 #include <sys/types.h> |
14 #include <sys/wait.h> | 14 #include <sys/wait.h> |
15 #include <time.h> | 15 #include <time.h> |
16 #include <unistd.h> | 16 #include <unistd.h> |
17 | 17 |
18 #include "base/file_util.h" | 18 #include "base/file_util.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/string_number_conversions.h" |
20 #include "base/string_tokenizer.h" | 21 #include "base/string_tokenizer.h" |
21 #include "base/string_util.h" | 22 #include "base/string_util.h" |
22 #include "base/sys_info.h" | 23 #include "base/sys_info.h" |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
26 enum ParsingState { | 27 enum ParsingState { |
27 KEY_NAME, | 28 KEY_NAME, |
28 KEY_VALUE | 29 KEY_VALUE |
29 }; | 30 }; |
30 | 31 |
31 // Reads /proc/<pid>/stat and populates |proc_stats| with the values split by | 32 // Reads /proc/<pid>/stat and populates |proc_stats| with the values split by |
32 // spaces. | 33 // spaces. |
33 void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { | 34 void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { |
34 FilePath stat_file("/proc"); | 35 FilePath stat_file("/proc"); |
35 stat_file = stat_file.Append(IntToString(pid)); | 36 stat_file = stat_file.Append(base::IntToString(pid)); |
36 stat_file = stat_file.Append("stat"); | 37 stat_file = stat_file.Append("stat"); |
37 std::string mem_stats; | 38 std::string mem_stats; |
38 if (!file_util::ReadFileToString(stat_file, &mem_stats)) | 39 if (!file_util::ReadFileToString(stat_file, &mem_stats)) |
39 return; | 40 return; |
40 SplitString(mem_stats, ' ', proc_stats); | 41 SplitString(mem_stats, ' ', proc_stats); |
41 } | 42 } |
42 | 43 |
43 } // namespace | 44 } // namespace |
44 | 45 |
45 namespace base { | 46 namespace base { |
46 | 47 |
47 ProcessId GetParentProcessId(ProcessHandle process) { | 48 ProcessId GetParentProcessId(ProcessHandle process) { |
48 FilePath stat_file("/proc"); | 49 FilePath stat_file("/proc"); |
49 stat_file = stat_file.Append(IntToString(process)); | 50 stat_file = stat_file.Append(base::IntToString(process)); |
50 stat_file = stat_file.Append("status"); | 51 stat_file = stat_file.Append("status"); |
51 std::string status; | 52 std::string status; |
52 if (!file_util::ReadFileToString(stat_file, &status)) | 53 if (!file_util::ReadFileToString(stat_file, &status)) |
53 return -1; | 54 return -1; |
54 | 55 |
55 StringTokenizer tokenizer(status, ":\n"); | 56 StringTokenizer tokenizer(status, ":\n"); |
56 ParsingState state = KEY_NAME; | 57 ParsingState state = KEY_NAME; |
57 std::string last_key_name; | 58 std::string last_key_name; |
58 while (tokenizer.GetNext()) { | 59 while (tokenizer.GetNext()) { |
59 switch (state) { | 60 switch (state) { |
60 case KEY_NAME: | 61 case KEY_NAME: |
61 last_key_name = tokenizer.token(); | 62 last_key_name = tokenizer.token(); |
62 state = KEY_VALUE; | 63 state = KEY_VALUE; |
63 break; | 64 break; |
64 case KEY_VALUE: | 65 case KEY_VALUE: |
65 DCHECK(!last_key_name.empty()); | 66 DCHECK(!last_key_name.empty()); |
66 if (last_key_name == "PPid") { | 67 if (last_key_name == "PPid") { |
67 pid_t ppid = StringToInt(tokenizer.token()); | 68 int ppid; |
| 69 base::StringToInt(tokenizer.token(), &ppid); |
68 return ppid; | 70 return ppid; |
69 } | 71 } |
70 state = KEY_NAME; | 72 state = KEY_NAME; |
71 break; | 73 break; |
72 } | 74 } |
73 } | 75 } |
74 NOTREACHED(); | 76 NOTREACHED(); |
75 return -1; | 77 return -1; |
76 } | 78 } |
77 | 79 |
78 FilePath GetProcessExecutablePath(ProcessHandle process) { | 80 FilePath GetProcessExecutablePath(ProcessHandle process) { |
79 FilePath stat_file("/proc"); | 81 FilePath stat_file("/proc"); |
80 stat_file = stat_file.Append(IntToString(process)); | 82 stat_file = stat_file.Append(base::IntToString(process)); |
81 stat_file = stat_file.Append("exe"); | 83 stat_file = stat_file.Append("exe"); |
82 char exename[2048]; | 84 char exename[2048]; |
83 ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); | 85 ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); |
84 if (len < 1) { | 86 if (len < 1) { |
85 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses | 87 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses |
86 return FilePath(); | 88 return FilePath(); |
87 } | 89 } |
88 return FilePath(std::string(exename, len)); | 90 return FilePath(std::string(exename, len)); |
89 } | 91 } |
90 | 92 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 // static | 200 // static |
199 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { | 201 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { |
200 return new ProcessMetrics(process); | 202 return new ProcessMetrics(process); |
201 } | 203 } |
202 | 204 |
203 // On linux, we return vsize. | 205 // On linux, we return vsize. |
204 size_t ProcessMetrics::GetPagefileUsage() const { | 206 size_t ProcessMetrics::GetPagefileUsage() const { |
205 std::vector<std::string> proc_stats; | 207 std::vector<std::string> proc_stats; |
206 GetProcStats(process_, &proc_stats); | 208 GetProcStats(process_, &proc_stats); |
207 const size_t kVmSize = 22; | 209 const size_t kVmSize = 22; |
208 if (proc_stats.size() > kVmSize) | 210 if (proc_stats.size() > kVmSize) { |
209 return static_cast<size_t>(StringToInt(proc_stats[kVmSize])); | 211 int vm_size; |
| 212 base::StringToInt(proc_stats[kVmSize], &vm_size); |
| 213 return static_cast<size_t>(vm_size); |
| 214 } |
210 return 0; | 215 return 0; |
211 } | 216 } |
212 | 217 |
213 // On linux, we return the high water mark of vsize. | 218 // On linux, we return the high water mark of vsize. |
214 size_t ProcessMetrics::GetPeakPagefileUsage() const { | 219 size_t ProcessMetrics::GetPeakPagefileUsage() const { |
215 std::vector<std::string> proc_stats; | 220 std::vector<std::string> proc_stats; |
216 GetProcStats(process_, &proc_stats); | 221 GetProcStats(process_, &proc_stats); |
217 const size_t kVmPeak = 21; | 222 const size_t kVmPeak = 21; |
218 if (proc_stats.size() > kVmPeak) | 223 if (proc_stats.size() > kVmPeak) { |
219 return static_cast<size_t>(StringToInt(proc_stats[kVmPeak])); | 224 int vm_peak; |
| 225 if (base::StringToInt(proc_stats[kVmPeak], &vm_peak)) |
| 226 return vm_peak; |
| 227 } |
220 return 0; | 228 return 0; |
221 } | 229 } |
222 | 230 |
223 // On linux, we return RSS. | 231 // On linux, we return RSS. |
224 size_t ProcessMetrics::GetWorkingSetSize() const { | 232 size_t ProcessMetrics::GetWorkingSetSize() const { |
225 std::vector<std::string> proc_stats; | 233 std::vector<std::string> proc_stats; |
226 GetProcStats(process_, &proc_stats); | 234 GetProcStats(process_, &proc_stats); |
227 const size_t kVmRss = 23; | 235 const size_t kVmRss = 23; |
228 if (proc_stats.size() > kVmRss) { | 236 if (proc_stats.size() > kVmRss) { |
229 size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss])); | 237 int num_pages; |
230 return num_pages * getpagesize(); | 238 if (base::StringToInt(proc_stats[kVmRss], &num_pages)) |
| 239 return static_cast<size_t>(num_pages) * getpagesize(); |
231 } | 240 } |
232 return 0; | 241 return 0; |
233 } | 242 } |
234 | 243 |
235 // On linux, we return the high water mark of RSS. | 244 // On linux, we return the high water mark of RSS. |
236 size_t ProcessMetrics::GetPeakWorkingSetSize() const { | 245 size_t ProcessMetrics::GetPeakWorkingSetSize() const { |
237 std::vector<std::string> proc_stats; | 246 std::vector<std::string> proc_stats; |
238 GetProcStats(process_, &proc_stats); | 247 GetProcStats(process_, &proc_stats); |
239 const size_t kVmHwm = 23; | 248 const size_t kVmHwm = 23; |
240 if (proc_stats.size() > kVmHwm) { | 249 if (proc_stats.size() > kVmHwm) { |
241 size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmHwm])); | 250 int num_pages; |
242 return num_pages * getpagesize(); | 251 base::StringToInt(proc_stats[kVmHwm], &num_pages); |
| 252 return static_cast<size_t>(num_pages) * getpagesize(); |
243 } | 253 } |
244 return 0; | 254 return 0; |
245 } | 255 } |
246 | 256 |
247 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, | 257 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, |
248 size_t* shared_bytes) { | 258 size_t* shared_bytes) { |
249 WorkingSetKBytes ws_usage; | 259 WorkingSetKBytes ws_usage; |
250 if (!GetWorkingSetKBytes(&ws_usage)) | 260 if (!GetWorkingSetKBytes(&ws_usage)) |
251 return false; | 261 return false; |
252 | 262 |
253 if (private_bytes) | 263 if (private_bytes) |
254 *private_bytes = ws_usage.priv << 10; | 264 *private_bytes = ws_usage.priv << 10; |
255 | 265 |
256 if (shared_bytes) | 266 if (shared_bytes) |
257 *shared_bytes = ws_usage.shared * 1024; | 267 *shared_bytes = ws_usage.shared * 1024; |
258 | 268 |
259 return true; | 269 return true; |
260 } | 270 } |
261 | 271 |
262 // Private and Shared working set sizes are obtained from /proc/<pid>/smaps. | 272 // Private and Shared working set sizes are obtained from /proc/<pid>/smaps. |
263 // When that's not available, use the values from /proc<pid>/statm as a | 273 // When that's not available, use the values from /proc<pid>/statm as a |
264 // close approximation. | 274 // close approximation. |
265 // See http://www.pixelbeat.org/scripts/ps_mem.py | 275 // See http://www.pixelbeat.org/scripts/ps_mem.py |
266 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { | 276 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
267 FilePath stat_file = | 277 FilePath stat_file = |
268 FilePath("/proc").Append(IntToString(process_)).Append("smaps"); | 278 FilePath("/proc").Append(base::IntToString(process_)).Append("smaps"); |
269 std::string smaps; | 279 std::string smaps; |
270 int private_kb = 0; | 280 int private_kb = 0; |
271 int pss_kb = 0; | 281 int pss_kb = 0; |
272 bool have_pss = false; | 282 bool have_pss = false; |
273 if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) { | 283 if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) { |
274 const std::string private_prefix = "Private_"; | 284 const std::string private_prefix = "Private_"; |
275 const std::string pss_prefix = "Pss"; | 285 const std::string pss_prefix = "Pss"; |
276 StringTokenizer tokenizer(smaps, ":\n"); | 286 StringTokenizer tokenizer(smaps, ":\n"); |
277 StringPiece last_key_name; | 287 StringPiece last_key_name; |
278 ParsingState state = KEY_NAME; | 288 ParsingState state = KEY_NAME; |
279 while (tokenizer.GetNext()) { | 289 while (tokenizer.GetNext()) { |
280 switch (state) { | 290 switch (state) { |
281 case KEY_NAME: | 291 case KEY_NAME: |
282 last_key_name = tokenizer.token_piece(); | 292 last_key_name = tokenizer.token_piece(); |
283 state = KEY_VALUE; | 293 state = KEY_VALUE; |
284 break; | 294 break; |
285 case KEY_VALUE: | 295 case KEY_VALUE: |
286 if (last_key_name.empty()) { | 296 if (last_key_name.empty()) { |
287 NOTREACHED(); | 297 NOTREACHED(); |
288 return false; | 298 return false; |
289 } | 299 } |
290 if (last_key_name.starts_with(private_prefix)) { | 300 if (last_key_name.starts_with(private_prefix)) { |
291 private_kb += StringToInt(tokenizer.token()); | 301 int cur; |
| 302 base::StringToInt(tokenizer.token(), &cur); |
| 303 private_kb += cur; |
292 } else if (last_key_name.starts_with(pss_prefix)) { | 304 } else if (last_key_name.starts_with(pss_prefix)) { |
293 have_pss = true; | 305 have_pss = true; |
294 pss_kb += StringToInt(tokenizer.token()); | 306 int cur; |
| 307 base::StringToInt(tokenizer.token(), &cur); |
| 308 pss_kb += cur; |
295 } | 309 } |
296 state = KEY_NAME; | 310 state = KEY_NAME; |
297 break; | 311 break; |
298 } | 312 } |
299 } | 313 } |
300 } else { | 314 } else { |
301 // Try statm if smaps is empty because of the SUID sandbox. | 315 // Try statm if smaps is empty because of the SUID sandbox. |
302 // First we need to get the page size though. | 316 // First we need to get the page size though. |
303 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; | 317 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; |
304 if (page_size_kb <= 0) | 318 if (page_size_kb <= 0) |
305 return false; | 319 return false; |
306 | 320 |
307 stat_file = | 321 stat_file = |
308 FilePath("/proc").Append(IntToString(process_)).Append("statm"); | 322 FilePath("/proc").Append(base::IntToString(process_)).Append("statm"); |
309 std::string statm; | 323 std::string statm; |
310 if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) | 324 if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) |
311 return false; | 325 return false; |
312 | 326 |
313 std::vector<std::string> statm_vec; | 327 std::vector<std::string> statm_vec; |
314 SplitString(statm, ' ', &statm_vec); | 328 SplitString(statm, ' ', &statm_vec); |
315 if (statm_vec.size() != 7) | 329 if (statm_vec.size() != 7) |
316 return false; // Not the format we expect. | 330 return false; // Not the format we expect. |
317 private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]); | 331 |
318 private_kb *= page_size_kb; | 332 int statm1, statm2; |
| 333 base::StringToInt(statm_vec[1], &statm1); |
| 334 base::StringToInt(statm_vec[2], &statm2); |
| 335 private_kb = (statm1 - statm2) * page_size_kb; |
319 } | 336 } |
320 ws_usage->priv = private_kb; | 337 ws_usage->priv = private_kb; |
321 // Sharable is not calculated, as it does not provide interesting data. | 338 // Sharable is not calculated, as it does not provide interesting data. |
322 ws_usage->shareable = 0; | 339 ws_usage->shareable = 0; |
323 | 340 |
324 ws_usage->shared = 0; | 341 ws_usage->shared = 0; |
325 if (have_pss) | 342 if (have_pss) |
326 ws_usage->shared = pss_kb; | 343 ws_usage->shared = pss_kb; |
327 return true; | 344 return true; |
328 } | 345 } |
329 | 346 |
330 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING | 347 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING |
331 // in your kernel configuration. | 348 // in your kernel configuration. |
332 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { | 349 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
333 std::string proc_io_contents; | 350 std::string proc_io_contents; |
334 FilePath io_file("/proc"); | 351 FilePath io_file("/proc"); |
335 io_file = io_file.Append(IntToString(process_)); | 352 io_file = io_file.Append(base::IntToString(process_)); |
336 io_file = io_file.Append("io"); | 353 io_file = io_file.Append("io"); |
337 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) | 354 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) |
338 return false; | 355 return false; |
339 | 356 |
340 (*io_counters).OtherOperationCount = 0; | 357 (*io_counters).OtherOperationCount = 0; |
341 (*io_counters).OtherTransferCount = 0; | 358 (*io_counters).OtherTransferCount = 0; |
342 | 359 |
343 StringTokenizer tokenizer(proc_io_contents, ": \n"); | 360 StringTokenizer tokenizer(proc_io_contents, ": \n"); |
344 ParsingState state = KEY_NAME; | 361 ParsingState state = KEY_NAME; |
345 std::string last_key_name; | 362 std::string last_key_name; |
346 while (tokenizer.GetNext()) { | 363 while (tokenizer.GetNext()) { |
347 switch (state) { | 364 switch (state) { |
348 case KEY_NAME: | 365 case KEY_NAME: |
349 last_key_name = tokenizer.token(); | 366 last_key_name = tokenizer.token(); |
350 state = KEY_VALUE; | 367 state = KEY_VALUE; |
351 break; | 368 break; |
352 case KEY_VALUE: | 369 case KEY_VALUE: |
353 DCHECK(!last_key_name.empty()); | 370 DCHECK(!last_key_name.empty()); |
354 if (last_key_name == "syscr") { | 371 if (last_key_name == "syscr") { |
355 (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token()); | 372 base::StringToInt64(tokenizer.token(), |
| 373 reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount)); |
356 } else if (last_key_name == "syscw") { | 374 } else if (last_key_name == "syscw") { |
357 (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token()); | 375 base::StringToInt64(tokenizer.token(), |
| 376 reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount)); |
358 } else if (last_key_name == "rchar") { | 377 } else if (last_key_name == "rchar") { |
359 (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token()); | 378 base::StringToInt64(tokenizer.token(), |
| 379 reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount)); |
360 } else if (last_key_name == "wchar") { | 380 } else if (last_key_name == "wchar") { |
361 (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token()); | 381 base::StringToInt64(tokenizer.token(), |
| 382 reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount)); |
362 } | 383 } |
363 state = KEY_NAME; | 384 state = KEY_NAME; |
364 break; | 385 break; |
365 } | 386 } |
366 } | 387 } |
367 return true; | 388 return true; |
368 } | 389 } |
369 | 390 |
370 | 391 |
371 // Exposed for testing. | 392 // Exposed for testing. |
372 int ParseProcStatCPU(const std::string& input) { | 393 int ParseProcStatCPU(const std::string& input) { |
373 // /proc/<pid>/stat contains the process name in parens. In case the | 394 // /proc/<pid>/stat contains the process name in parens. In case the |
374 // process name itself contains parens, skip past them. | 395 // process name itself contains parens, skip past them. |
375 std::string::size_type rparen = input.rfind(')'); | 396 std::string::size_type rparen = input.rfind(')'); |
376 if (rparen == std::string::npos) | 397 if (rparen == std::string::npos) |
377 return -1; | 398 return -1; |
378 | 399 |
379 // From here, we expect a bunch of space-separated fields, where the | 400 // From here, we expect a bunch of space-separated fields, where the |
380 // 0-indexed 11th and 12th are utime and stime. On two different machines | 401 // 0-indexed 11th and 12th are utime and stime. On two different machines |
381 // I found 42 and 39 fields, so let's just expect the ones we need. | 402 // I found 42 and 39 fields, so let's just expect the ones we need. |
382 std::vector<std::string> fields; | 403 std::vector<std::string> fields; |
383 SplitString(input.substr(rparen + 2), ' ', &fields); | 404 SplitString(input.substr(rparen + 2), ' ', &fields); |
384 if (fields.size() < 13) | 405 if (fields.size() < 13) |
385 return -1; // Output not in the format we expect. | 406 return -1; // Output not in the format we expect. |
386 | 407 |
387 return StringToInt(fields[11]) + StringToInt(fields[12]); | 408 int fields11, fields12; |
| 409 base::StringToInt(fields[11], &fields11); |
| 410 base::StringToInt(fields[12], &fields12); |
| 411 return fields11 + fields12; |
388 } | 412 } |
389 | 413 |
390 // Get the total CPU of a single process. Return value is number of jiffies | 414 // Get the total CPU of a single process. Return value is number of jiffies |
391 // on success or -1 on error. | 415 // on success or -1 on error. |
392 static int GetProcessCPU(pid_t pid) { | 416 static int GetProcessCPU(pid_t pid) { |
393 // Use /proc/<pid>/task to find all threads and parse their /stat file. | 417 // Use /proc/<pid>/task to find all threads and parse their /stat file. |
394 FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid)); | 418 FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid)); |
395 | 419 |
396 DIR* dir = opendir(path.value().c_str()); | 420 DIR* dir = opendir(path.value().c_str()); |
397 if (!dir) { | 421 if (!dir) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 LOG(WARNING) << "Failed to parse /proc/meminfo. Only found " << | 515 LOG(WARNING) << "Failed to parse /proc/meminfo. Only found " << |
492 meminfo_fields.size() << " fields."; | 516 meminfo_fields.size() << " fields."; |
493 return 0; | 517 return 0; |
494 } | 518 } |
495 | 519 |
496 DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:"); | 520 DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:"); |
497 DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:"); | 521 DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:"); |
498 DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); | 522 DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); |
499 DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:"); | 523 DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:"); |
500 | 524 |
501 size_t result_in_kb; | 525 int mem_total, mem_free, mem_buffers, mem_cache; |
502 result_in_kb = StringToInt(meminfo_fields[kMemTotalIndex]); | 526 base::StringToInt(meminfo_fields[kMemTotalIndex], &mem_total); |
503 result_in_kb -= StringToInt(meminfo_fields[kMemFreeIndex]); | 527 base::StringToInt(meminfo_fields[kMemFreeIndex], &mem_free); |
504 result_in_kb -= StringToInt(meminfo_fields[kMemBuffersIndex]); | 528 base::StringToInt(meminfo_fields[kMemBuffersIndex], &mem_buffers); |
505 result_in_kb -= StringToInt(meminfo_fields[kMemCacheIndex]); | 529 base::StringToInt(meminfo_fields[kMemCacheIndex], &mem_cache); |
506 | 530 |
507 return result_in_kb; | 531 return mem_total - mem_free - mem_buffers - mem_cache; |
508 } | 532 } |
509 | 533 |
510 namespace { | 534 namespace { |
511 | 535 |
512 void OnNoMemorySize(size_t size) { | 536 void OnNoMemorySize(size_t size) { |
513 if (size != 0) | 537 if (size != 0) |
514 LOG(FATAL) << "Out of memory, size = " << size; | 538 LOG(FATAL) << "Out of memory, size = " << size; |
515 LOG(FATAL) << "Out of memory."; | 539 LOG(FATAL) << "Out of memory."; |
516 } | 540 } |
517 | 541 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 std::set_new_handler(&OnNoMemory); | 630 std::set_new_handler(&OnNoMemory); |
607 // If we're using glibc's allocator, the above functions will override | 631 // If we're using glibc's allocator, the above functions will override |
608 // malloc and friends and make them die on out of memory. | 632 // malloc and friends and make them die on out of memory. |
609 } | 633 } |
610 | 634 |
611 bool AdjustOOMScore(ProcessId process, int score) { | 635 bool AdjustOOMScore(ProcessId process, int score) { |
612 if (score < 0 || score > 15) | 636 if (score < 0 || score > 15) |
613 return false; | 637 return false; |
614 | 638 |
615 FilePath oom_adj("/proc"); | 639 FilePath oom_adj("/proc"); |
616 oom_adj = oom_adj.Append(Int64ToString(process)); | 640 oom_adj = oom_adj.Append(base::Int64ToString(process)); |
617 oom_adj = oom_adj.AppendASCII("oom_adj"); | 641 oom_adj = oom_adj.AppendASCII("oom_adj"); |
618 | 642 |
619 if (!file_util::PathExists(oom_adj)) | 643 if (!file_util::PathExists(oom_adj)) |
620 return false; | 644 return false; |
621 | 645 |
622 std::string score_str = IntToString(score); | 646 std::string score_str = base::IntToString(score); |
623 return (static_cast<int>(score_str.length()) == | 647 return (static_cast<int>(score_str.length()) == |
624 file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); | 648 file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); |
625 } | 649 } |
626 | 650 |
627 } // namespace base | 651 } // namespace base |
OLD | NEW |