[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/process/process_metrics.h" |
| 6 | |
| 7 | #include <windows.h> |
| 8 | #include <psapi.h> |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 9 | #include <stddef.h> |
| 10 | #include <stdint.h> |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 11 | #include <winternl.h> |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 12 | |
dcheng | 0917ec4 | 2015-11-19 07:00:20 | [diff] [blame] | 13 | #include <algorithm> |
| 14 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 15 | #include "base/logging.h" |
thestig | 0df2bae8 | 2016-07-26 17:59:36 | [diff] [blame] | 16 | #include "base/memory/ptr_util.h" |
stanisc | 75ab212 | 2016-09-09 02:20:53 | [diff] [blame] | 17 | #include "base/process/memory.h" |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 18 | #include "base/sys_info.h" |
| 19 | |
keishi | 12b598b9 | 2017-06-20 10:25:26 | [diff] [blame] | 20 | #if defined(OS_WIN) |
| 21 | #include <windows.h> |
| 22 | #endif |
| 23 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 24 | namespace base { |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 25 | namespace { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 26 | |
| 27 | // System pagesize. This value remains constant on x86/64 architectures. |
| 28 | const int PAGESIZE_KB = 4; |
| 29 | |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 30 | typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( |
| 31 | SYSTEM_INFORMATION_CLASS SystemInformationClass, |
| 32 | PVOID SystemInformation, |
| 33 | ULONG SystemInformationLength, |
| 34 | PULONG ReturnLength); |
| 35 | |
| 36 | } // namespace |
| 37 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 38 | ProcessMetrics::~ProcessMetrics() { } |
| 39 | |
Chris Mumford | a7fd9f07 | 2017-09-12 00:20:51 | [diff] [blame^] | 40 | size_t GetMaxFds() { |
| 41 | // Windows is only limited by the amount of physical memory. |
| 42 | return std::numeric_limits<size_t>::max(); |
| 43 | } |
| 44 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 45 | // static |
thestig | 0df2bae8 | 2016-07-26 17:59:36 | [diff] [blame] | 46 | std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( |
| 47 | ProcessHandle process) { |
| 48 | return WrapUnique(new ProcessMetrics(process)); |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | size_t ProcessMetrics::GetPagefileUsage() const { |
| 52 | PROCESS_MEMORY_COUNTERS pmc; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 53 | if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 54 | return pmc.PagefileUsage; |
| 55 | } |
| 56 | return 0; |
| 57 | } |
| 58 | |
| 59 | // Returns the peak space allocated for the pagefile, in bytes. |
| 60 | size_t ProcessMetrics::GetPeakPagefileUsage() const { |
| 61 | PROCESS_MEMORY_COUNTERS pmc; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 62 | if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 63 | return pmc.PeakPagefileUsage; |
| 64 | } |
| 65 | return 0; |
| 66 | } |
| 67 | |
| 68 | // Returns the current working set size, in bytes. |
| 69 | size_t ProcessMetrics::GetWorkingSetSize() const { |
| 70 | PROCESS_MEMORY_COUNTERS pmc; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 71 | if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 72 | return pmc.WorkingSetSize; |
| 73 | } |
| 74 | return 0; |
| 75 | } |
| 76 | |
| 77 | // Returns the peak working set size, in bytes. |
| 78 | size_t ProcessMetrics::GetPeakWorkingSetSize() const { |
| 79 | PROCESS_MEMORY_COUNTERS pmc; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 80 | if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 81 | return pmc.PeakWorkingSetSize; |
| 82 | } |
| 83 | return 0; |
| 84 | } |
| 85 | |
| 86 | bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, |
erikchen | 5672241 | 2017-03-13 22:46:49 | [diff] [blame] | 87 | size_t* shared_bytes) const { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 88 | // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2. |
| 89 | // GetProcessMemoryInfo() will simply fail on prior OS. So the requested |
| 90 | // information is simply not available. Hence, we will return 0 on unsupported |
| 91 | // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member. |
| 92 | PROCESS_MEMORY_COUNTERS_EX pmcx; |
| 93 | if (private_bytes && |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 94 | GetProcessMemoryInfo(process_.Get(), |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 95 | reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), |
| 96 | sizeof(pmcx))) { |
| 97 | *private_bytes = pmcx.PrivateUsage; |
| 98 | } |
| 99 | |
| 100 | if (shared_bytes) { |
| 101 | WorkingSetKBytes ws_usage; |
| 102 | if (!GetWorkingSetKBytes(&ws_usage)) |
| 103 | return false; |
| 104 | |
| 105 | *shared_bytes = ws_usage.shared * 1024; |
| 106 | } |
| 107 | |
| 108 | return true; |
| 109 | } |
| 110 | |
| 111 | void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { |
| 112 | MEMORY_BASIC_INFORMATION mbi = {0}; |
| 113 | size_t committed_private = 0; |
| 114 | size_t committed_mapped = 0; |
| 115 | size_t committed_image = 0; |
| 116 | void* base_address = NULL; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 117 | while (VirtualQueryEx(process_.Get(), base_address, &mbi, sizeof(mbi)) == |
| 118 | sizeof(mbi)) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 119 | if (mbi.State == MEM_COMMIT) { |
| 120 | if (mbi.Type == MEM_PRIVATE) { |
| 121 | committed_private += mbi.RegionSize; |
| 122 | } else if (mbi.Type == MEM_MAPPED) { |
| 123 | committed_mapped += mbi.RegionSize; |
| 124 | } else if (mbi.Type == MEM_IMAGE) { |
| 125 | committed_image += mbi.RegionSize; |
| 126 | } else { |
| 127 | NOTREACHED(); |
| 128 | } |
| 129 | } |
| 130 | void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize; |
| 131 | // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION. |
| 132 | // If we query 64bit processes in a 32bit process, VirtualQueryEx() |
| 133 | // returns such data. |
| 134 | if (new_base <= base_address) { |
| 135 | usage->image = 0; |
| 136 | usage->mapped = 0; |
| 137 | usage->priv = 0; |
| 138 | return; |
| 139 | } |
| 140 | base_address = new_base; |
| 141 | } |
| 142 | usage->image = committed_image / 1024; |
| 143 | usage->mapped = committed_mapped / 1024; |
| 144 | usage->priv = committed_private / 1024; |
| 145 | } |
| 146 | |
stanisc | 75ab212 | 2016-09-09 02:20:53 | [diff] [blame] | 147 | namespace { |
| 148 | |
| 149 | class WorkingSetInformationBuffer { |
| 150 | public: |
| 151 | WorkingSetInformationBuffer() {} |
| 152 | ~WorkingSetInformationBuffer() { Clear(); } |
| 153 | |
| 154 | bool Reserve(size_t size) { |
| 155 | Clear(); |
| 156 | // Use UncheckedMalloc here because this can be called from the code |
| 157 | // that handles low memory condition. |
| 158 | return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_)); |
| 159 | } |
| 160 | |
stanisc | 75ab212 | 2016-09-09 02:20:53 | [diff] [blame] | 161 | const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; } |
| 162 | |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 163 | size_t GetPageEntryCount() const { return number_of_entries; } |
| 164 | |
| 165 | // This function is used to get page entries for a process. |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 166 | bool QueryPageEntries(const ProcessHandle& process) { |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 167 | int retries = 5; |
| 168 | number_of_entries = 4096; // Just a guess. |
| 169 | |
| 170 | for (;;) { |
| 171 | size_t buffer_size = |
| 172 | sizeof(PSAPI_WORKING_SET_INFORMATION) + |
| 173 | (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); |
| 174 | |
| 175 | if (!Reserve(buffer_size)) |
| 176 | return false; |
| 177 | |
| 178 | // On success, |buffer_| is populated with info about the working set of |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 179 | // |process|. On ERROR_BAD_LENGTH failure, increase the size of the |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 180 | // buffer and try again. |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 181 | if (QueryWorkingSet(process, buffer_, buffer_size)) |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 182 | break; // Success |
| 183 | |
| 184 | if (GetLastError() != ERROR_BAD_LENGTH) |
| 185 | return false; |
| 186 | |
| 187 | number_of_entries = buffer_->NumberOfEntries; |
| 188 | |
| 189 | // Maybe some entries are being added right now. Increase the buffer to |
| 190 | // take that into account. Increasing by 10% should generally be enough, |
| 191 | // especially considering the potentially low memory condition during the |
| 192 | // call (when called from OomMemoryDetails) and the potentially high |
| 193 | // number of entries (300K was observed in crash dumps). |
| 194 | number_of_entries *= 1.1; |
| 195 | |
| 196 | if (--retries == 0) { |
| 197 | // If we're looping, eventually fail. |
| 198 | return false; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | // TODO(chengx): Remove the comment and the logic below. It is no longer |
| 203 | // needed since we don't have Win2000 support. |
| 204 | // On windows 2000 the function returns 1 even when the buffer is too small. |
| 205 | // The number of entries that we are going to parse is the minimum between |
| 206 | // the size we allocated and the real number of entries. |
| 207 | number_of_entries = std::min(number_of_entries, |
| 208 | static_cast<size_t>(buffer_->NumberOfEntries)); |
| 209 | |
| 210 | return true; |
| 211 | } |
| 212 | |
stanisc | 75ab212 | 2016-09-09 02:20:53 | [diff] [blame] | 213 | private: |
| 214 | void Clear() { |
| 215 | free(buffer_); |
| 216 | buffer_ = nullptr; |
| 217 | } |
| 218 | |
| 219 | PSAPI_WORKING_SET_INFORMATION* buffer_ = nullptr; |
| 220 | |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 221 | // Number of page entries. |
| 222 | size_t number_of_entries = 0; |
| 223 | |
stanisc | 75ab212 | 2016-09-09 02:20:53 | [diff] [blame] | 224 | DISALLOW_COPY_AND_ASSIGN(WorkingSetInformationBuffer); |
| 225 | }; |
| 226 | |
| 227 | } // namespace |
| 228 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 229 | bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
| 230 | size_t ws_private = 0; |
| 231 | size_t ws_shareable = 0; |
| 232 | size_t ws_shared = 0; |
| 233 | |
| 234 | DCHECK(ws_usage); |
| 235 | memset(ws_usage, 0, sizeof(*ws_usage)); |
| 236 | |
stanisc | 75ab212 | 2016-09-09 02:20:53 | [diff] [blame] | 237 | WorkingSetInformationBuffer buffer; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 238 | if (!buffer.QueryPageEntries(process_.Get())) |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 239 | return false; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 240 | |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 241 | size_t num_page_entries = buffer.GetPageEntryCount(); |
| 242 | for (size_t i = 0; i < num_page_entries; i++) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 243 | if (buffer->WorkingSetInfo[i].Shared) { |
| 244 | ws_shareable++; |
| 245 | if (buffer->WorkingSetInfo[i].ShareCount > 1) |
| 246 | ws_shared++; |
| 247 | } else { |
| 248 | ws_private++; |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | ws_usage->priv = ws_private * PAGESIZE_KB; |
| 253 | ws_usage->shareable = ws_shareable * PAGESIZE_KB; |
| 254 | ws_usage->shared = ws_shared * PAGESIZE_KB; |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 255 | |
| 256 | return true; |
| 257 | } |
| 258 | |
| 259 | // This function calculates the proportional set size for a process. |
| 260 | bool ProcessMetrics::GetProportionalSetSizeBytes(uint64_t* pss_bytes) const { |
| 261 | double ws_pss = 0.0; |
| 262 | |
| 263 | WorkingSetInformationBuffer buffer; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 264 | if (!buffer.QueryPageEntries(process_.Get())) |
chengx | b1728927 | 2016-12-12 06:55:56 | [diff] [blame] | 265 | return false; |
| 266 | |
| 267 | size_t num_page_entries = buffer.GetPageEntryCount(); |
| 268 | for (size_t i = 0; i < num_page_entries; i++) { |
| 269 | if (buffer->WorkingSetInfo[i].Shared && |
| 270 | buffer->WorkingSetInfo[i].ShareCount > 0) |
| 271 | ws_pss += 1.0 / buffer->WorkingSetInfo[i].ShareCount; |
| 272 | else |
| 273 | ws_pss += 1.0; |
| 274 | } |
| 275 | |
| 276 | *pss_bytes = static_cast<uint64_t>(ws_pss * GetPageSize()); |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 277 | return true; |
| 278 | } |
| 279 | |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 280 | static uint64_t FileTimeToUTC(const FILETIME& ftime) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 281 | LARGE_INTEGER li; |
| 282 | li.LowPart = ftime.dwLowDateTime; |
| 283 | li.HighPart = ftime.dwHighDateTime; |
| 284 | return li.QuadPart; |
| 285 | } |
| 286 | |
Wez | 4ae8f29 | 2017-09-11 20:52:03 | [diff] [blame] | 287 | double ProcessMetrics::GetPlatformIndependentCPUUsage() { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 288 | FILETIME creation_time; |
| 289 | FILETIME exit_time; |
| 290 | FILETIME kernel_time; |
| 291 | FILETIME user_time; |
| 292 | |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 293 | if (!GetProcessTimes(process_.Get(), &creation_time, &exit_time, &kernel_time, |
| 294 | &user_time)) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 295 | // We don't assert here because in some cases (such as in the Task Manager) |
| 296 | // we may call this function on a process that has just exited but we have |
| 297 | // not yet received the notification. |
| 298 | return 0; |
| 299 | } |
Wez | 4ae8f29 | 2017-09-11 20:52:03 | [diff] [blame] | 300 | int64_t system_time = FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time); |
[email protected] | e21c332 | 2014-04-06 21:25:01 | [diff] [blame] | 301 | TimeTicks time = TimeTicks::Now(); |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 302 | |
[email protected] | e21c332 | 2014-04-06 21:25:01 | [diff] [blame] | 303 | if (last_system_time_ == 0) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 304 | // First call, just set the last values. |
| 305 | last_system_time_ = system_time; |
[email protected] | ac6d065 | 2014-01-14 00:06:37 | [diff] [blame] | 306 | last_cpu_time_ = time; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 307 | return 0; |
| 308 | } |
| 309 | |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 310 | int64_t system_time_delta = system_time - last_system_time_; |
[email protected] | e21c332 | 2014-04-06 21:25:01 | [diff] [blame] | 311 | // FILETIME is in 100-nanosecond units, so this needs microseconds times 10. |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 312 | int64_t time_delta = (time - last_cpu_time_).InMicroseconds() * 10; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 313 | DCHECK_NE(0U, time_delta); |
| 314 | if (time_delta == 0) |
| 315 | return 0; |
| 316 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 317 | |
| 318 | last_system_time_ = system_time; |
[email protected] | ac6d065 | 2014-01-14 00:06:37 | [diff] [blame] | 319 | last_cpu_time_ = time; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 320 | |
Wez | 4ae8f29 | 2017-09-11 20:52:03 | [diff] [blame] | 321 | return static_cast<double>(system_time_delta) / time_delta; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 322 | } |
| 323 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 324 | bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 325 | return GetProcessIoCounters(process_.Get(), io_counters) != FALSE; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 326 | } |
| 327 | |
Wez | 4ae8f29 | 2017-09-11 20:52:03 | [diff] [blame] | 328 | ProcessMetrics::ProcessMetrics(ProcessHandle process) : last_system_time_(0) { |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 329 | if (process) { |
| 330 | HANDLE duplicate_handle; |
| 331 | BOOL result = ::DuplicateHandle(::GetCurrentProcess(), process, |
| 332 | ::GetCurrentProcess(), &duplicate_handle, |
| 333 | PROCESS_QUERY_INFORMATION, FALSE, 0); |
| 334 | DCHECK(result); |
| 335 | process_.Set(duplicate_handle); |
| 336 | } |
| 337 | } |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 338 | |
| 339 | size_t GetSystemCommitCharge() { |
| 340 | // Get the System Page Size. |
| 341 | SYSTEM_INFO system_info; |
| 342 | GetSystemInfo(&system_info); |
| 343 | |
| 344 | PERFORMANCE_INFORMATION info; |
thestig | 0df2bae8 | 2016-07-26 17:59:36 | [diff] [blame] | 345 | if (!GetPerformanceInfo(&info, sizeof(info))) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 346 | DLOG(ERROR) << "Failed to fetch internal performance info."; |
| 347 | return 0; |
| 348 | } |
| 349 | return (info.CommitTotal * system_info.dwPageSize) / 1024; |
| 350 | } |
| 351 | |
reveman | 1fef3ffc | 2014-12-18 19:22:28 | [diff] [blame] | 352 | size_t GetPageSize() { |
| 353 | return PAGESIZE_KB * 1024; |
| 354 | } |
| 355 | |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 356 | // This function uses the following mapping between MEMORYSTATUSEX and |
| 357 | // SystemMemoryInfoKB: |
| 358 | // ullTotalPhys ==> total |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 359 | // ullAvailPhys ==> avail_phys |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 360 | // ullTotalPageFile ==> swap_total |
| 361 | // ullAvailPageFile ==> swap_free |
| 362 | bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { |
| 363 | MEMORYSTATUSEX mem_status; |
| 364 | mem_status.dwLength = sizeof(mem_status); |
| 365 | if (!::GlobalMemoryStatusEx(&mem_status)) |
| 366 | return false; |
| 367 | |
| 368 | meminfo->total = mem_status.ullTotalPhys / 1024; |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 369 | meminfo->avail_phys = mem_status.ullAvailPhys / 1024; |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 370 | meminfo->swap_total = mem_status.ullTotalPageFile / 1024; |
| 371 | meminfo->swap_free = mem_status.ullAvailPageFile / 1024; |
| 372 | |
| 373 | return true; |
| 374 | } |
| 375 | |
keishi | 12b598b9 | 2017-06-20 10:25:26 | [diff] [blame] | 376 | size_t ProcessMetrics::GetMallocUsage() { |
Keishi Hattori | 8cc2c3ab | 2017-08-04 20:55:30 | [diff] [blame] | 377 | // Unsupported as getting malloc usage on Windows requires iterating through |
| 378 | // the heap which is slow and crashes. |
| 379 | return 0; |
keishi | 12b598b9 | 2017-06-20 10:25:26 | [diff] [blame] | 380 | } |
| 381 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 382 | } // namespace base |