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

Side by Side Diff: base/process/process_metrics_win.cc

Issue 2779413002: Duplicate process handle in process_metrics_win.cc (Closed)
Patch Set: Used ScopedHandle Created 3 years, 8 months 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
« no previous file with comments | « base/process/process_metrics.h ('k') | no next file » | 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) 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
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/process/process_metrics.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698