| 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 |