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

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

Issue 2549803003: Add function to compute proportional set size for OS_WIN (Closed)
Patch Set: Fix compile error for std::min Created 4 years 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
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 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 WorkingSetInformationBuffer() {} 148 WorkingSetInformationBuffer() {}
149 ~WorkingSetInformationBuffer() { Clear(); } 149 ~WorkingSetInformationBuffer() { Clear(); }
150 150
151 bool Reserve(size_t size) { 151 bool Reserve(size_t size) {
152 Clear(); 152 Clear();
153 // Use UncheckedMalloc here because this can be called from the code 153 // Use UncheckedMalloc here because this can be called from the code
154 // that handles low memory condition. 154 // that handles low memory condition.
155 return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_)); 155 return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_));
156 } 156 }
157 157
158 PSAPI_WORKING_SET_INFORMATION* get() { return buffer_; }
159 const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; } 158 const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; }
160 159
160 size_t GetPageEntryCount() const { return number_of_entries; }
161
162 // This function is used to get page entries for a process.
163 bool QueryPageEntries(const ProcessHandle& process_) {
164 int retries = 5;
165 number_of_entries = 4096; // Just a guess.
166
167 for (;;) {
168 size_t buffer_size =
169 sizeof(PSAPI_WORKING_SET_INFORMATION) +
170 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
171
172 if (!Reserve(buffer_size))
173 return false;
174
175 // On success, |buffer_| is populated with info about the working set of
176 // |process_|. On ERROR_BAD_LENGTH failure, increase the size of the
177 // buffer and try again.
178 if (QueryWorkingSet(process_, buffer_, buffer_size))
179 break; // Success
180
181 if (GetLastError() != ERROR_BAD_LENGTH)
182 return false;
183
184 number_of_entries = buffer_->NumberOfEntries;
185
186 // Maybe some entries are being added right now. Increase the buffer to
187 // take that into account. Increasing by 10% should generally be enough,
188 // especially considering the potentially low memory condition during the
189 // call (when called from OomMemoryDetails) and the potentially high
190 // number of entries (300K was observed in crash dumps).
191 number_of_entries *= 1.1;
192
193 if (--retries == 0) {
194 // If we're looping, eventually fail.
195 return false;
196 }
197 }
198
199 // TODO(chengx): Remove the comment and the logic below. It is no longer
200 // needed since we don't have Win2000 support.
201 // On windows 2000 the function returns 1 even when the buffer is too small.
202 // The number of entries that we are going to parse is the minimum between
203 // the size we allocated and the real number of entries.
204 number_of_entries = std::min(number_of_entries,
205 static_cast<size_t>(buffer_->NumberOfEntries));
206
207 return true;
208 }
209
161 private: 210 private:
162 void Clear() { 211 void Clear() {
163 free(buffer_); 212 free(buffer_);
164 buffer_ = nullptr; 213 buffer_ = nullptr;
165 } 214 }
166 215
167 PSAPI_WORKING_SET_INFORMATION* buffer_ = nullptr; 216 PSAPI_WORKING_SET_INFORMATION* buffer_ = nullptr;
168 217
218 // Number of page entries.
219 size_t number_of_entries = 0;
220
169 DISALLOW_COPY_AND_ASSIGN(WorkingSetInformationBuffer); 221 DISALLOW_COPY_AND_ASSIGN(WorkingSetInformationBuffer);
170 }; 222 };
171 223
172 } // namespace 224 } // namespace
173 225
174 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { 226 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
175 size_t ws_private = 0; 227 size_t ws_private = 0;
176 size_t ws_shareable = 0; 228 size_t ws_shareable = 0;
177 size_t ws_shared = 0; 229 size_t ws_shared = 0;
178 230
179 DCHECK(ws_usage); 231 DCHECK(ws_usage);
180 memset(ws_usage, 0, sizeof(*ws_usage)); 232 memset(ws_usage, 0, sizeof(*ws_usage));
181 233
182 DWORD number_of_entries = 4096; // Just a guess.
183 WorkingSetInformationBuffer buffer; 234 WorkingSetInformationBuffer buffer;
184 int retries = 5; 235 if (!buffer.QueryPageEntries(process_))
185 for (;;) { 236 return false;
186 DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
187 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
188 237
189 if (!buffer.Reserve(buffer_size)) 238 size_t num_page_entries = buffer.GetPageEntryCount();
190 return false; 239 for (size_t i = 0; i < num_page_entries; i++) {
191
192 // Call the function once to get number of items
193 if (QueryWorkingSet(process_, buffer.get(), buffer_size))
194 break; // Success
195
196 if (GetLastError() != ERROR_BAD_LENGTH)
197 return false;
198
199 number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
200
201 // Maybe some entries are being added right now. Increase the buffer to
202 // take that into account. Increasing by 10% should generally be enough,
203 // especially considering the potentially low memory condition during the
204 // call (when called from OomMemoryDetails) and the potentially high
205 // number of entries (300K was observed in crash dumps).
206 number_of_entries = static_cast<DWORD>(number_of_entries * 1.1);
207
208 if (--retries == 0) {
209 // If we're looping, eventually fail.
210 return false;
211 }
212 }
213
214 // On windows 2000 the function returns 1 even when the buffer is too small.
215 // The number of entries that we are going to parse is the minimum between the
216 // size we allocated and the real number of entries.
217 number_of_entries =
218 std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
219 for (unsigned int i = 0; i < number_of_entries; i++) {
220 if (buffer->WorkingSetInfo[i].Shared) { 240 if (buffer->WorkingSetInfo[i].Shared) {
221 ws_shareable++; 241 ws_shareable++;
222 if (buffer->WorkingSetInfo[i].ShareCount > 1) 242 if (buffer->WorkingSetInfo[i].ShareCount > 1)
223 ws_shared++; 243 ws_shared++;
224 } else { 244 } else {
225 ws_private++; 245 ws_private++;
226 } 246 }
227 } 247 }
228 248
229 ws_usage->priv = ws_private * PAGESIZE_KB; 249 ws_usage->priv = ws_private * PAGESIZE_KB;
230 ws_usage->shareable = ws_shareable * PAGESIZE_KB; 250 ws_usage->shareable = ws_shareable * PAGESIZE_KB;
231 ws_usage->shared = ws_shared * PAGESIZE_KB; 251 ws_usage->shared = ws_shared * PAGESIZE_KB;
252
232 return true; 253 return true;
233 } 254 }
234 255
256 // This function calculates the proportional set size for a process.
257 bool ProcessMetrics::GetProportionalSetSizeBytes(uint64_t* pss_bytes) const {
258 double ws_pss = 0.0;
259
260 WorkingSetInformationBuffer buffer;
261 if (!buffer.QueryPageEntries(process_))
262 return false;
263
264 size_t num_page_entries = buffer.GetPageEntryCount();
265 for (size_t i = 0; i < num_page_entries; i++) {
266 if (buffer->WorkingSetInfo[i].Shared &&
267 buffer->WorkingSetInfo[i].ShareCount > 0)
268 ws_pss += 1.0 / buffer->WorkingSetInfo[i].ShareCount;
269 else
270 ws_pss += 1.0;
271 }
272
273 *pss_bytes = static_cast<uint64_t>(ws_pss * GetPageSize());
274 return true;
275 }
276
235 static uint64_t FileTimeToUTC(const FILETIME& ftime) { 277 static uint64_t FileTimeToUTC(const FILETIME& ftime) {
236 LARGE_INTEGER li; 278 LARGE_INTEGER li;
237 li.LowPart = ftime.dwLowDateTime; 279 li.LowPart = ftime.dwLowDateTime;
238 li.HighPart = ftime.dwHighDateTime; 280 li.HighPart = ftime.dwHighDateTime;
239 return li.QuadPart; 281 return li.QuadPart;
240 } 282 }
241 283
242 double ProcessMetrics::GetCPUUsage() { 284 double ProcessMetrics::GetCPUUsage() {
243 FILETIME creation_time; 285 FILETIME creation_time;
244 FILETIME exit_time; 286 FILETIME exit_time;
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 360
319 meminfo->total = mem_status.ullTotalPhys / 1024; 361 meminfo->total = mem_status.ullTotalPhys / 1024;
320 meminfo->free = mem_status.ullAvailPhys / 1024; 362 meminfo->free = mem_status.ullAvailPhys / 1024;
321 meminfo->swap_total = mem_status.ullTotalPageFile / 1024; 363 meminfo->swap_total = mem_status.ullTotalPageFile / 1024;
322 meminfo->swap_free = mem_status.ullAvailPageFile / 1024; 364 meminfo->swap_free = mem_status.ullAvailPageFile / 1024;
323 365
324 return true; 366 return true;
325 } 367 }
326 368
327 } // namespace base 369 } // namespace base
OLDNEW
« no previous file with comments | « base/process/process_metrics.h ('k') | components/tracing/common/process_metrics_memory_dump_provider.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698