| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/process_metrics.h" | 5 #include "base/process/process_metrics.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <psapi.h> | 8 #include <psapi.h> |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 #include <stdint.h> | 10 #include <stdint.h> |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 ProcessMetrics::~ProcessMetrics() { } | 34 ProcessMetrics::~ProcessMetrics() { } |
| 35 | 35 |
| 36 // static | 36 // static |
| 37 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( | 37 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( |
| 38 ProcessHandle process) { | 38 ProcessHandle process) { |
| 39 return WrapUnique(new ProcessMetrics(process)); | 39 return WrapUnique(new ProcessMetrics(process)); |
| 40 } | 40 } |
| 41 | 41 |
| 42 size_t ProcessMetrics::GetPagefileUsage() const { | 42 size_t ProcessMetrics::GetPagefileUsage() const { |
| 43 PROCESS_MEMORY_COUNTERS pmc; | 43 PROCESS_MEMORY_COUNTERS pmc; |
| 44 if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { | 44 if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
| 45 return pmc.PagefileUsage; | 45 return pmc.PagefileUsage; |
| 46 } | 46 } |
| 47 return 0; | 47 return 0; |
| 48 } | 48 } |
| 49 | 49 |
| 50 // Returns the peak space allocated for the pagefile, in bytes. | 50 // Returns the peak space allocated for the pagefile, in bytes. |
| 51 size_t ProcessMetrics::GetPeakPagefileUsage() const { | 51 size_t ProcessMetrics::GetPeakPagefileUsage() const { |
| 52 PROCESS_MEMORY_COUNTERS pmc; | 52 PROCESS_MEMORY_COUNTERS pmc; |
| 53 if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { | 53 if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
| 54 return pmc.PeakPagefileUsage; | 54 return pmc.PeakPagefileUsage; |
| 55 } | 55 } |
| 56 return 0; | 56 return 0; |
| 57 } | 57 } |
| 58 | 58 |
| 59 // Returns the current working set size, in bytes. | 59 // Returns the current working set size, in bytes. |
| 60 size_t ProcessMetrics::GetWorkingSetSize() const { | 60 size_t ProcessMetrics::GetWorkingSetSize() const { |
| 61 PROCESS_MEMORY_COUNTERS pmc; | 61 PROCESS_MEMORY_COUNTERS pmc; |
| 62 if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { | 62 if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
| 63 return pmc.WorkingSetSize; | 63 return pmc.WorkingSetSize; |
| 64 } | 64 } |
| 65 return 0; | 65 return 0; |
| 66 } | 66 } |
| 67 | 67 |
| 68 // Returns the peak working set size, in bytes. | 68 // Returns the peak working set size, in bytes. |
| 69 size_t ProcessMetrics::GetPeakWorkingSetSize() const { | 69 size_t ProcessMetrics::GetPeakWorkingSetSize() const { |
| 70 PROCESS_MEMORY_COUNTERS pmc; | 70 PROCESS_MEMORY_COUNTERS pmc; |
| 71 if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { | 71 if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
| 72 return pmc.PeakWorkingSetSize; | 72 return pmc.PeakWorkingSetSize; |
| 73 } | 73 } |
| 74 return 0; | 74 return 0; |
| 75 } | 75 } |
| 76 | 76 |
| 77 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, | 77 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, |
| 78 size_t* shared_bytes) const { | 78 size_t* shared_bytes) const { |
| 79 // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2. | 79 // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2. |
| 80 // GetProcessMemoryInfo() will simply fail on prior OS. So the requested | 80 // GetProcessMemoryInfo() will simply fail on prior OS. So the requested |
| 81 // information is simply not available. Hence, we will return 0 on unsupported | 81 // information is simply not available. Hence, we will return 0 on unsupported |
| 82 // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member. | 82 // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member. |
| 83 PROCESS_MEMORY_COUNTERS_EX pmcx; | 83 PROCESS_MEMORY_COUNTERS_EX pmcx; |
| 84 if (private_bytes && | 84 if (private_bytes && |
| 85 GetProcessMemoryInfo(process_, | 85 GetProcessMemoryInfo(process_.Get(), |
| 86 reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), | 86 reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), |
| 87 sizeof(pmcx))) { | 87 sizeof(pmcx))) { |
| 88 *private_bytes = pmcx.PrivateUsage; | 88 *private_bytes = pmcx.PrivateUsage; |
| 89 } | 89 } |
| 90 | 90 |
| 91 if (shared_bytes) { | 91 if (shared_bytes) { |
| 92 WorkingSetKBytes ws_usage; | 92 WorkingSetKBytes ws_usage; |
| 93 if (!GetWorkingSetKBytes(&ws_usage)) | 93 if (!GetWorkingSetKBytes(&ws_usage)) |
| 94 return false; | 94 return false; |
| 95 | 95 |
| 96 *shared_bytes = ws_usage.shared * 1024; | 96 *shared_bytes = ws_usage.shared * 1024; |
| 97 } | 97 } |
| 98 | 98 |
| 99 return true; | 99 return true; |
| 100 } | 100 } |
| 101 | 101 |
| 102 void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { | 102 void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { |
| 103 MEMORY_BASIC_INFORMATION mbi = {0}; | 103 MEMORY_BASIC_INFORMATION mbi = {0}; |
| 104 size_t committed_private = 0; | 104 size_t committed_private = 0; |
| 105 size_t committed_mapped = 0; | 105 size_t committed_mapped = 0; |
| 106 size_t committed_image = 0; | 106 size_t committed_image = 0; |
| 107 void* base_address = NULL; | 107 void* base_address = NULL; |
| 108 while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) == | 108 while (VirtualQueryEx(process_.Get(), base_address, &mbi, sizeof(mbi)) == |
| 109 sizeof(mbi)) { | 109 sizeof(mbi)) { |
| 110 if (mbi.State == MEM_COMMIT) { | 110 if (mbi.State == MEM_COMMIT) { |
| 111 if (mbi.Type == MEM_PRIVATE) { | 111 if (mbi.Type == MEM_PRIVATE) { |
| 112 committed_private += mbi.RegionSize; | 112 committed_private += mbi.RegionSize; |
| 113 } else if (mbi.Type == MEM_MAPPED) { | 113 } else if (mbi.Type == MEM_MAPPED) { |
| 114 committed_mapped += mbi.RegionSize; | 114 committed_mapped += mbi.RegionSize; |
| 115 } else if (mbi.Type == MEM_IMAGE) { | 115 } else if (mbi.Type == MEM_IMAGE) { |
| 116 committed_image += mbi.RegionSize; | 116 committed_image += mbi.RegionSize; |
| 117 } else { | 117 } else { |
| 118 NOTREACHED(); | 118 NOTREACHED(); |
| 119 } | 119 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 147 // Use UncheckedMalloc here because this can be called from the code | 147 // Use UncheckedMalloc here because this can be called from the code |
| 148 // that handles low memory condition. | 148 // that handles low memory condition. |
| 149 return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_)); | 149 return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_)); |
| 150 } | 150 } |
| 151 | 151 |
| 152 const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; } | 152 const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; } |
| 153 | 153 |
| 154 size_t GetPageEntryCount() const { return number_of_entries; } | 154 size_t GetPageEntryCount() const { return number_of_entries; } |
| 155 | 155 |
| 156 // This function is used to get page entries for a process. | 156 // This function is used to get page entries for a process. |
| 157 bool QueryPageEntries(const ProcessHandle& process_) { | 157 bool QueryPageEntries(const ProcessHandle& process) { |
| 158 int retries = 5; | 158 int retries = 5; |
| 159 number_of_entries = 4096; // Just a guess. | 159 number_of_entries = 4096; // Just a guess. |
| 160 | 160 |
| 161 for (;;) { | 161 for (;;) { |
| 162 size_t buffer_size = | 162 size_t buffer_size = |
| 163 sizeof(PSAPI_WORKING_SET_INFORMATION) + | 163 sizeof(PSAPI_WORKING_SET_INFORMATION) + |
| 164 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); | 164 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); |
| 165 | 165 |
| 166 if (!Reserve(buffer_size)) | 166 if (!Reserve(buffer_size)) |
| 167 return false; | 167 return false; |
| 168 | 168 |
| 169 // On success, |buffer_| is populated with info about the working set of | 169 // On success, |buffer_| is populated with info about the working set of |
| 170 // |process_|. On ERROR_BAD_LENGTH failure, increase the size of the | 170 // |process|. On ERROR_BAD_LENGTH failure, increase the size of the |
| 171 // buffer and try again. | 171 // buffer and try again. |
| 172 if (QueryWorkingSet(process_, buffer_, buffer_size)) | 172 if (QueryWorkingSet(process, buffer_, buffer_size)) |
| 173 break; // Success | 173 break; // Success |
| 174 | 174 |
| 175 if (GetLastError() != ERROR_BAD_LENGTH) | 175 if (GetLastError() != ERROR_BAD_LENGTH) |
| 176 return false; | 176 return false; |
| 177 | 177 |
| 178 number_of_entries = buffer_->NumberOfEntries; | 178 number_of_entries = buffer_->NumberOfEntries; |
| 179 | 179 |
| 180 // Maybe some entries are being added right now. Increase the buffer to | 180 // Maybe some entries are being added right now. Increase the buffer to |
| 181 // take that into account. Increasing by 10% should generally be enough, | 181 // take that into account. Increasing by 10% should generally be enough, |
| 182 // especially considering the potentially low memory condition during the | 182 // especially considering the potentially low memory condition during the |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 | 219 |
| 220 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { | 220 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
| 221 size_t ws_private = 0; | 221 size_t ws_private = 0; |
| 222 size_t ws_shareable = 0; | 222 size_t ws_shareable = 0; |
| 223 size_t ws_shared = 0; | 223 size_t ws_shared = 0; |
| 224 | 224 |
| 225 DCHECK(ws_usage); | 225 DCHECK(ws_usage); |
| 226 memset(ws_usage, 0, sizeof(*ws_usage)); | 226 memset(ws_usage, 0, sizeof(*ws_usage)); |
| 227 | 227 |
| 228 WorkingSetInformationBuffer buffer; | 228 WorkingSetInformationBuffer buffer; |
| 229 if (!buffer.QueryPageEntries(process_)) | 229 if (!buffer.QueryPageEntries(process_.Get())) |
| 230 return false; | 230 return false; |
| 231 | 231 |
| 232 size_t num_page_entries = buffer.GetPageEntryCount(); | 232 size_t num_page_entries = buffer.GetPageEntryCount(); |
| 233 for (size_t i = 0; i < num_page_entries; i++) { | 233 for (size_t i = 0; i < num_page_entries; i++) { |
| 234 if (buffer->WorkingSetInfo[i].Shared) { | 234 if (buffer->WorkingSetInfo[i].Shared) { |
| 235 ws_shareable++; | 235 ws_shareable++; |
| 236 if (buffer->WorkingSetInfo[i].ShareCount > 1) | 236 if (buffer->WorkingSetInfo[i].ShareCount > 1) |
| 237 ws_shared++; | 237 ws_shared++; |
| 238 } else { | 238 } else { |
| 239 ws_private++; | 239 ws_private++; |
| 240 } | 240 } |
| 241 } | 241 } |
| 242 | 242 |
| 243 ws_usage->priv = ws_private * PAGESIZE_KB; | 243 ws_usage->priv = ws_private * PAGESIZE_KB; |
| 244 ws_usage->shareable = ws_shareable * PAGESIZE_KB; | 244 ws_usage->shareable = ws_shareable * PAGESIZE_KB; |
| 245 ws_usage->shared = ws_shared * PAGESIZE_KB; | 245 ws_usage->shared = ws_shared * PAGESIZE_KB; |
| 246 | 246 |
| 247 return true; | 247 return true; |
| 248 } | 248 } |
| 249 | 249 |
| 250 // This function calculates the proportional set size for a process. | 250 // This function calculates the proportional set size for a process. |
| 251 bool ProcessMetrics::GetProportionalSetSizeBytes(uint64_t* pss_bytes) const { | 251 bool ProcessMetrics::GetProportionalSetSizeBytes(uint64_t* pss_bytes) const { |
| 252 double ws_pss = 0.0; | 252 double ws_pss = 0.0; |
| 253 | 253 |
| 254 WorkingSetInformationBuffer buffer; | 254 WorkingSetInformationBuffer buffer; |
| 255 if (!buffer.QueryPageEntries(process_)) | 255 if (!buffer.QueryPageEntries(process_.Get())) |
| 256 return false; | 256 return false; |
| 257 | 257 |
| 258 size_t num_page_entries = buffer.GetPageEntryCount(); | 258 size_t num_page_entries = buffer.GetPageEntryCount(); |
| 259 for (size_t i = 0; i < num_page_entries; i++) { | 259 for (size_t i = 0; i < num_page_entries; i++) { |
| 260 if (buffer->WorkingSetInfo[i].Shared && | 260 if (buffer->WorkingSetInfo[i].Shared && |
| 261 buffer->WorkingSetInfo[i].ShareCount > 0) | 261 buffer->WorkingSetInfo[i].ShareCount > 0) |
| 262 ws_pss += 1.0 / buffer->WorkingSetInfo[i].ShareCount; | 262 ws_pss += 1.0 / buffer->WorkingSetInfo[i].ShareCount; |
| 263 else | 263 else |
| 264 ws_pss += 1.0; | 264 ws_pss += 1.0; |
| 265 } | 265 } |
| 266 | 266 |
| 267 *pss_bytes = static_cast<uint64_t>(ws_pss * GetPageSize()); | 267 *pss_bytes = static_cast<uint64_t>(ws_pss * GetPageSize()); |
| 268 return true; | 268 return true; |
| 269 } | 269 } |
| 270 | 270 |
| 271 static uint64_t FileTimeToUTC(const FILETIME& ftime) { | 271 static uint64_t FileTimeToUTC(const FILETIME& ftime) { |
| 272 LARGE_INTEGER li; | 272 LARGE_INTEGER li; |
| 273 li.LowPart = ftime.dwLowDateTime; | 273 li.LowPart = ftime.dwLowDateTime; |
| 274 li.HighPart = ftime.dwHighDateTime; | 274 li.HighPart = ftime.dwHighDateTime; |
| 275 return li.QuadPart; | 275 return li.QuadPart; |
| 276 } | 276 } |
| 277 | 277 |
| 278 double ProcessMetrics::GetCPUUsage() { | 278 double ProcessMetrics::GetCPUUsage() { |
| 279 FILETIME creation_time; | 279 FILETIME creation_time; |
| 280 FILETIME exit_time; | 280 FILETIME exit_time; |
| 281 FILETIME kernel_time; | 281 FILETIME kernel_time; |
| 282 FILETIME user_time; | 282 FILETIME user_time; |
| 283 | 283 |
| 284 if (!GetProcessTimes(process_, &creation_time, &exit_time, | 284 if (!GetProcessTimes(process_.Get(), &creation_time, &exit_time, &kernel_time, |
| 285 &kernel_time, &user_time)) { | 285 &user_time)) { |
| 286 // We don't assert here because in some cases (such as in the Task Manager) | 286 // We don't assert here because in some cases (such as in the Task Manager) |
| 287 // we may call this function on a process that has just exited but we have | 287 // we may call this function on a process that has just exited but we have |
| 288 // not yet received the notification. | 288 // not yet received the notification. |
| 289 return 0; | 289 return 0; |
| 290 } | 290 } |
| 291 int64_t system_time = | 291 int64_t system_time = |
| 292 (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) / | 292 (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) / |
| 293 processor_count_; | 293 processor_count_; |
| 294 TimeTicks time = TimeTicks::Now(); | 294 TimeTicks time = TimeTicks::Now(); |
| 295 | 295 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 308 return 0; | 308 return 0; |
| 309 | 309 |
| 310 | 310 |
| 311 last_system_time_ = system_time; | 311 last_system_time_ = system_time; |
| 312 last_cpu_time_ = time; | 312 last_cpu_time_ = time; |
| 313 | 313 |
| 314 return static_cast<double>(system_time_delta * 100.0) / time_delta; | 314 return static_cast<double>(system_time_delta * 100.0) / time_delta; |
| 315 } | 315 } |
| 316 | 316 |
| 317 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { | 317 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
| 318 return GetProcessIoCounters(process_, io_counters) != FALSE; | 318 return GetProcessIoCounters(process_.Get(), io_counters) != FALSE; |
| 319 } | 319 } |
| 320 | 320 |
| 321 ProcessMetrics::ProcessMetrics(ProcessHandle process) | 321 ProcessMetrics::ProcessMetrics(ProcessHandle process) |
| 322 : process_(process), | 322 : processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0) { |
| 323 processor_count_(SysInfo::NumberOfProcessors()), | 323 if (process) { |
| 324 last_system_time_(0) {} | 324 HANDLE duplicate_handle; |
| 325 BOOL result = ::DuplicateHandle(::GetCurrentProcess(), process, |
| 326 ::GetCurrentProcess(), &duplicate_handle, |
| 327 PROCESS_QUERY_INFORMATION, FALSE, 0); |
| 328 DCHECK(result); |
| 329 process_.Set(duplicate_handle); |
| 330 } |
| 331 } |
| 325 | 332 |
| 326 size_t GetSystemCommitCharge() { | 333 size_t GetSystemCommitCharge() { |
| 327 // Get the System Page Size. | 334 // Get the System Page Size. |
| 328 SYSTEM_INFO system_info; | 335 SYSTEM_INFO system_info; |
| 329 GetSystemInfo(&system_info); | 336 GetSystemInfo(&system_info); |
| 330 | 337 |
| 331 PERFORMANCE_INFORMATION info; | 338 PERFORMANCE_INFORMATION info; |
| 332 if (!GetPerformanceInfo(&info, sizeof(info))) { | 339 if (!GetPerformanceInfo(&info, sizeof(info))) { |
| 333 DLOG(ERROR) << "Failed to fetch internal performance info."; | 340 DLOG(ERROR) << "Failed to fetch internal performance info."; |
| 334 return 0; | 341 return 0; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 354 | 361 |
| 355 meminfo->total = mem_status.ullTotalPhys / 1024; | 362 meminfo->total = mem_status.ullTotalPhys / 1024; |
| 356 meminfo->avail_phys = mem_status.ullAvailPhys / 1024; | 363 meminfo->avail_phys = mem_status.ullAvailPhys / 1024; |
| 357 meminfo->swap_total = mem_status.ullTotalPageFile / 1024; | 364 meminfo->swap_total = mem_status.ullTotalPageFile / 1024; |
| 358 meminfo->swap_free = mem_status.ullAvailPageFile / 1024; | 365 meminfo->swap_free = mem_status.ullAvailPageFile / 1024; |
| 359 | 366 |
| 360 return true; | 367 return true; |
| 361 } | 368 } |
| 362 | 369 |
| 363 } // namespace base | 370 } // namespace base |
| OLD | NEW |