Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 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 | |
Bruce Dawson | aa08ad82 | 2018-01-20 00:31:05 | [diff] [blame] | 7 | #include <windows.h> // Must be in front of other Windows header files. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 8 | #include <winternl.h> |
Bruce Dawson | aa08ad82 | 2018-01-20 00:31:05 | [diff] [blame] | 9 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 10 | #include <psapi.h> |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 11 | #include <stddef.h> |
| 12 | #include <stdint.h> |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 13 | |
dcheng | 0917ec4 | 2015-11-19 07:00:20 | [diff] [blame] | 14 | #include <algorithm> |
| 15 | |
Joe Mason | cddff4c9 | 2024-10-03 13:59:00 | [diff] [blame] | 16 | #include "base/check.h" |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 17 | #include "base/logging.h" |
thestig | 0df2bae8 | 2016-07-26 17:59:36 | [diff] [blame] | 18 | #include "base/memory/ptr_util.h" |
Joe Mason | a0ba58b05 | 2023-02-22 20:46:29 | [diff] [blame] | 19 | #include "base/notreached.h" |
Sebastien Marchand | 75a7cdf | 2018-11-13 23:47:03 | [diff] [blame] | 20 | #include "base/system/sys_info.h" |
Sebastien Marchand | 05183ceb | 2018-10-30 02:20:04 | [diff] [blame] | 21 | #include "base/threading/scoped_blocking_call.h" |
Etienne Pierre-doray | fc7952f0 | 2025-06-06 00:04:33 | [diff] [blame] | 22 | #include "base/trace_event/trace_event.h" |
Hans Wennborg | 9e7d902 | 2021-05-03 12:56:20 | [diff] [blame] | 23 | #include "base/values.h" |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 24 | #include "build/build_config.h" |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 25 | |
| 26 | namespace base { |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 27 | namespace { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 28 | |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 29 | // ntstatus.h conflicts with windows.h so define this locally. |
| 30 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) |
| 31 | |
| 32 | // Definition of this struct is taken from the book: |
| 33 | // Windows NT/200, Native API reference, Gary Nebbett |
| 34 | struct SYSTEM_PERFORMANCE_INFORMATION { |
| 35 | // Total idle time of all processes in the system (units of 100 ns). |
| 36 | LARGE_INTEGER IdleTime; |
| 37 | // Number of bytes read (by all call to ZwReadFile). |
| 38 | LARGE_INTEGER ReadTransferCount; |
| 39 | // Number of bytes written (by all call to ZwWriteFile). |
| 40 | LARGE_INTEGER WriteTransferCount; |
| 41 | // Number of bytes transferred (e.g. DeviceIoControlFile) |
| 42 | LARGE_INTEGER OtherTransferCount; |
| 43 | // The amount of read operations. |
| 44 | ULONG ReadOperationCount; |
| 45 | // The amount of write operations. |
| 46 | ULONG WriteOperationCount; |
| 47 | // The amount of other operations. |
| 48 | ULONG OtherOperationCount; |
Sebastien Marchand | 57c036da | 2018-10-04 20:53:20 | [diff] [blame] | 49 | // The number of pages of physical memory available to processes running on |
| 50 | // the system. |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 51 | ULONG AvailablePages; |
| 52 | ULONG TotalCommittedPages; |
| 53 | ULONG TotalCommitLimit; |
| 54 | ULONG PeakCommitment; |
| 55 | ULONG PageFaults; |
| 56 | ULONG WriteCopyFaults; |
| 57 | ULONG TransitionFaults; |
| 58 | ULONG CacheTransitionFaults; |
| 59 | ULONG DemandZeroFaults; |
Sebastien Marchand | 57c036da | 2018-10-04 20:53:20 | [diff] [blame] | 60 | // The number of pages read from disk to resolve page faults. |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 61 | ULONG PagesRead; |
Sebastien Marchand | 57c036da | 2018-10-04 20:53:20 | [diff] [blame] | 62 | // The number of read operations initiated to resolve page faults. |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 63 | ULONG PageReadIos; |
| 64 | ULONG CacheReads; |
| 65 | ULONG CacheIos; |
| 66 | // The number of pages written to the system's pagefiles. |
| 67 | ULONG PagefilePagesWritten; |
| 68 | // The number of write operations performed on the system's pagefiles. |
| 69 | ULONG PagefilePageWriteIos; |
| 70 | ULONG MappedFilePagesWritten; |
| 71 | ULONG MappedFilePageWriteIos; |
| 72 | ULONG PagedPoolUsage; |
| 73 | ULONG NonPagedPoolUsage; |
| 74 | ULONG PagedPoolAllocs; |
| 75 | ULONG PagedPoolFrees; |
| 76 | ULONG NonPagedPoolAllocs; |
| 77 | ULONG NonPagedPoolFrees; |
| 78 | ULONG TotalFreeSystemPtes; |
| 79 | ULONG SystemCodePage; |
| 80 | ULONG TotalSystemDriverPages; |
| 81 | ULONG TotalSystemCodePages; |
| 82 | ULONG SmallNonPagedLookasideListAllocateHits; |
| 83 | ULONG SmallPagedLookasideListAllocateHits; |
| 84 | ULONG Reserved3; |
| 85 | ULONG MmSystemCachePage; |
| 86 | ULONG PagedPoolPage; |
| 87 | ULONG SystemDriverPage; |
| 88 | ULONG FastReadNoWait; |
| 89 | ULONG FastReadWait; |
| 90 | ULONG FastReadResourceMiss; |
| 91 | ULONG FastReadNotPossible; |
| 92 | ULONG FastMdlReadNoWait; |
| 93 | ULONG FastMdlReadWait; |
| 94 | ULONG FastMdlReadResourceMiss; |
| 95 | ULONG FastMdlReadNotPossible; |
| 96 | ULONG MapDataNoWait; |
| 97 | ULONG MapDataWait; |
| 98 | ULONG MapDataNoWaitMiss; |
| 99 | ULONG MapDataWaitMiss; |
| 100 | ULONG PinMappedDataCount; |
| 101 | ULONG PinReadNoWait; |
| 102 | ULONG PinReadWait; |
| 103 | ULONG PinReadNoWaitMiss; |
| 104 | ULONG PinReadWaitMiss; |
| 105 | ULONG CopyReadNoWait; |
| 106 | ULONG CopyReadWait; |
| 107 | ULONG CopyReadNoWaitMiss; |
| 108 | ULONG CopyReadWaitMiss; |
| 109 | ULONG MdlReadNoWait; |
| 110 | ULONG MdlReadWait; |
| 111 | ULONG MdlReadNoWaitMiss; |
| 112 | ULONG MdlReadWaitMiss; |
| 113 | ULONG ReadAheadIos; |
| 114 | ULONG LazyWriteIos; |
| 115 | ULONG LazyWritePages; |
| 116 | ULONG DataFlushes; |
| 117 | ULONG DataPages; |
| 118 | ULONG ContextSwitches; |
| 119 | ULONG FirstLevelTbFills; |
| 120 | ULONG SecondLevelTbFills; |
| 121 | ULONG SystemCalls; |
| 122 | }; |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 123 | |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 124 | base::expected<TimeDelta, ProcessCPUUsageError> GetImpreciseCumulativeCPUUsage( |
Joe Mason | ba14528 | 2024-03-12 20:18:19 | [diff] [blame] | 125 | const win::ScopedHandle& process) { |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 126 | FILETIME creation_time; |
| 127 | FILETIME exit_time; |
| 128 | FILETIME kernel_time; |
| 129 | FILETIME user_time; |
| 130 | |
| 131 | if (!process.is_valid()) { |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 132 | return base::unexpected(ProcessCPUUsageError::kSystemError); |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | if (!GetProcessTimes(process.get(), &creation_time, &exit_time, &kernel_time, |
| 136 | &user_time)) { |
| 137 | // This should never fail when the handle is valid. |
Joe Mason | cddff4c9 | 2024-10-03 13:59:00 | [diff] [blame] | 138 | NOTREACHED(); |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 139 | } |
| 140 | |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 141 | return base::ok(TimeDelta::FromFileTime(kernel_time) + |
| 142 | TimeDelta::FromFileTime(user_time)); |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 143 | } |
| 144 | |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 145 | } // namespace |
| 146 | |
Chris Mumford | a7fd9f07 | 2017-09-12 00:20:51 | [diff] [blame] | 147 | size_t GetMaxFds() { |
| 148 | // Windows is only limited by the amount of physical memory. |
| 149 | return std::numeric_limits<size_t>::max(); |
| 150 | } |
| 151 | |
Matthew Cary | 144069d | 2019-07-11 19:26:17 | [diff] [blame] | 152 | size_t GetHandleLimit() { |
| 153 | // Rounded down from value reported here: |
| 154 | // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx |
| 155 | return static_cast<size_t>(1 << 23); |
| 156 | } |
| 157 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 158 | // static |
thestig | 0df2bae8 | 2016-07-26 17:59:36 | [diff] [blame] | 159 | std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( |
| 160 | ProcessHandle process) { |
| 161 | return WrapUnique(new ProcessMetrics(process)); |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 162 | } |
| 163 | |
Etienne Pierre-doray | 490c80f | 2024-12-05 00:30:14 | [diff] [blame] | 164 | base::expected<ProcessMemoryInfo, ProcessUsageError> |
| 165 | ProcessMetrics::GetMemoryInfo() const { |
| 166 | if (!process_.is_valid()) { |
| 167 | return base::unexpected(ProcessUsageError::kProcessNotFound); |
| 168 | } |
| 169 | PROCESS_MEMORY_COUNTERS_EX pmc; |
| 170 | if (!::GetProcessMemoryInfo(process_.get(), |
| 171 | reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), |
| 172 | sizeof(pmc))) { |
| 173 | return base::unexpected(ProcessUsageError::kSystemError); |
| 174 | } |
| 175 | ProcessMemoryInfo counters; |
| 176 | counters.private_bytes = pmc.PrivateUsage; |
| 177 | counters.resident_set_bytes = pmc.WorkingSetSize; |
| 178 | return counters; |
| 179 | } |
| 180 | |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 181 | base::expected<TimeDelta, ProcessCPUUsageError> |
| 182 | ProcessMetrics::GetCumulativeCPUUsage() { |
Joe Mason | 122e628a | 2025-05-12 18:01:00 | [diff] [blame] | 183 | TRACE_EVENT("base", "GetCumulativeCPUUsage"); |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 184 | #if defined(ARCH_CPU_ARM64) |
| 185 | // Precise CPU usage is not available on Arm CPUs because they don't support |
| 186 | // constant rate TSC. |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 187 | return GetImpreciseCumulativeCPUUsage(process_); |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 188 | #else // !defined(ARCH_CPU_ARM64) |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 189 | if (!time_internal::HasConstantRateTSC()) { |
| 190 | return GetImpreciseCumulativeCPUUsage(process_); |
| 191 | } |
Patrick Monette | 2597b7c | 2022-06-08 23:30:17 | [diff] [blame] | 192 | |
Joe Mason | 9d02fe3 | 2023-06-06 20:16:23 | [diff] [blame] | 193 | const double tsc_ticks_per_second = time_internal::TSCTicksPerSecond(); |
| 194 | if (tsc_ticks_per_second == 0) { |
| 195 | // TSC is only initialized once TSCTicksPerSecond() is called twice 50 ms |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 196 | // apart on the same thread to get a baseline. In unit tests, it is frequent |
| 197 | // for the initialization not to be complete. In production, it can also |
| 198 | // theoretically happen. |
| 199 | return GetImpreciseCumulativeCPUUsage(process_); |
Joe Mason | 9d02fe3 | 2023-06-06 20:16:23 | [diff] [blame] | 200 | } |
| 201 | |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 202 | if (!process_.is_valid()) { |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 203 | return base::unexpected(ProcessCPUUsageError::kProcessNotFound); |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 204 | } |
| 205 | |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 206 | ULONG64 process_cycle_time = 0; |
| 207 | if (!QueryProcessCycleTime(process_.get(), &process_cycle_time)) { |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 208 | // This should never fail when the handle is valid. |
Joe Mason | cddff4c9 | 2024-10-03 13:59:00 | [diff] [blame] | 209 | NOTREACHED(); |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 210 | } |
| 211 | |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 212 | const double process_time_seconds = process_cycle_time / tsc_ticks_per_second; |
Joe Mason | 550eed6 | 2024-03-25 18:07:31 | [diff] [blame] | 213 | return base::ok(Seconds(process_time_seconds)); |
Patrick Monette | 24972c4 | 2022-04-14 02:34:00 | [diff] [blame] | 214 | #endif // !defined(ARCH_CPU_ARM64) |
| 215 | } |
| 216 | |
Sigurdur Asgeirsson | eb27eae7 | 2018-05-16 15:29:10 | [diff] [blame] | 217 | ProcessMetrics::ProcessMetrics(ProcessHandle process) { |
Joe Mason | cddff4c9 | 2024-10-03 13:59:00 | [diff] [blame] | 218 | if (process == kNullProcessHandle) { |
| 219 | // Don't try to duplicate an invalid handle. However, INVALID_HANDLE_VALUE |
| 220 | // is also the pseudo-handle returned by ::GetCurrentProcess(), so DO try |
| 221 | // to duplicate that. |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 222 | return; |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 223 | } |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 224 | HANDLE duplicate_handle = INVALID_HANDLE_VALUE; |
Joe Mason | 9bccdad | 2024-03-27 08:47:49 | [diff] [blame] | 225 | BOOL result = ::DuplicateHandle(::GetCurrentProcess(), process, |
| 226 | ::GetCurrentProcess(), &duplicate_handle, |
| 227 | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, 0); |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 228 | if (!result) { |
Joe Mason | cddff4c9 | 2024-10-03 13:59:00 | [diff] [blame] | 229 | // Even with PROCESS_QUERY_LIMITED_INFORMATION, DuplicateHandle can fail |
| 230 | // with ERROR_ACCESS_DENIED. And it's always possible to run out of handles. |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 231 | const DWORD last_error = ::GetLastError(); |
Joe Mason | cddff4c9 | 2024-10-03 13:59:00 | [diff] [blame] | 232 | CHECK(last_error == ERROR_ACCESS_DENIED || |
| 233 | last_error == ERROR_NO_SYSTEM_RESOURCES); |
Joe Mason | a678c4a2 | 2024-02-20 16:28:31 | [diff] [blame] | 234 | return; |
| 235 | } |
| 236 | |
| 237 | process_.Set(duplicate_handle); |
stanisc | e73f1a4 | 2017-03-31 21:42:22 | [diff] [blame] | 238 | } |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 239 | |
| 240 | size_t GetSystemCommitCharge() { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 241 | PERFORMANCE_INFORMATION info; |
Rulong Chen(陈汝龙) | 6d2bae1c | 2025-03-25 12:39:49 | [diff] [blame] | 242 | if (!::GetPerformanceInfo(&info, sizeof(info))) { |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 243 | DLOG(ERROR) << "Failed to fetch internal performance info."; |
| 244 | return 0; |
| 245 | } |
Rulong Chen(陈汝龙) | 6d2bae1c | 2025-03-25 12:39:49 | [diff] [blame] | 246 | return (info.CommitTotal * info.PageSize) / 1024; |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 247 | } |
| 248 | |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 249 | // This function uses the following mapping between MEMORYSTATUSEX and |
| 250 | // SystemMemoryInfoKB: |
| 251 | // ullTotalPhys ==> total |
mkolom | 01ac10b | 2017-03-22 01:47:29 | [diff] [blame] | 252 | // ullAvailPhys ==> avail_phys |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 253 | // ullTotalPageFile ==> swap_total |
| 254 | // ullAvailPageFile ==> swap_free |
| 255 | bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { |
| 256 | MEMORYSTATUSEX mem_status; |
| 257 | mem_status.dwLength = sizeof(mem_status); |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 258 | if (!::GlobalMemoryStatusEx(&mem_status)) { |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 259 | return false; |
Joe Mason | abed99e9 | 2024-03-04 22:04:13 | [diff] [blame] | 260 | } |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 261 | |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 262 | meminfo->total = saturated_cast<int>(mem_status.ullTotalPhys / 1024); |
| 263 | meminfo->avail_phys = saturated_cast<int>(mem_status.ullAvailPhys / 1024); |
| 264 | meminfo->swap_total = saturated_cast<int>(mem_status.ullTotalPageFile / 1024); |
| 265 | meminfo->swap_free = saturated_cast<int>(mem_status.ullAvailPageFile / 1024); |
georgesak | 7144e04 | 2015-07-29 17:11:42 | [diff] [blame] | 266 | |
| 267 | return true; |
| 268 | } |
| 269 | |
keishi | 12b598b9 | 2017-06-20 10:25:26 | [diff] [blame] | 270 | size_t ProcessMetrics::GetMallocUsage() { |
Keishi Hattori | 8cc2c3a | 2017-08-04 20:55:30 | [diff] [blame] | 271 | // Unsupported as getting malloc usage on Windows requires iterating through |
| 272 | // the heap which is slow and crashes. |
| 273 | return 0; |
keishi | 12b598b9 | 2017-06-20 10:25:26 | [diff] [blame] | 274 | } |
| 275 | |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 276 | SystemPerformanceInfo::SystemPerformanceInfo() = default; |
| 277 | SystemPerformanceInfo::SystemPerformanceInfo( |
| 278 | const SystemPerformanceInfo& other) = default; |
Arthur Eubanks | 08f7b054 | 2022-09-16 00:53:01 | [diff] [blame] | 279 | SystemPerformanceInfo& SystemPerformanceInfo::operator=( |
| 280 | const SystemPerformanceInfo& other) = default; |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 281 | |
Roman Sorokin | a8cf50eb6 | 2023-01-18 11:22:26 | [diff] [blame] | 282 | Value::Dict SystemPerformanceInfo::ToDict() const { |
| 283 | Value::Dict result; |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 284 | |
| 285 | // Write out uint64_t variables as doubles. |
| 286 | // Note: this may discard some precision, but for JS there's no other option. |
Roman Sorokin | a8cf50eb6 | 2023-01-18 11:22:26 | [diff] [blame] | 287 | result.Set("idle_time", strict_cast<double>(idle_time)); |
| 288 | result.Set("read_transfer_count", strict_cast<double>(read_transfer_count)); |
| 289 | result.Set("write_transfer_count", strict_cast<double>(write_transfer_count)); |
| 290 | result.Set("other_transfer_count", strict_cast<double>(other_transfer_count)); |
| 291 | result.Set("read_operation_count", strict_cast<double>(read_operation_count)); |
| 292 | result.Set("write_operation_count", |
| 293 | strict_cast<double>(write_operation_count)); |
| 294 | result.Set("other_operation_count", |
| 295 | strict_cast<double>(other_operation_count)); |
| 296 | result.Set("pagefile_pages_written", |
| 297 | strict_cast<double>(pagefile_pages_written)); |
| 298 | result.Set("pagefile_pages_write_ios", |
| 299 | strict_cast<double>(pagefile_pages_write_ios)); |
| 300 | result.Set("available_pages", strict_cast<double>(available_pages)); |
| 301 | result.Set("pages_read", strict_cast<double>(pages_read)); |
| 302 | result.Set("page_read_ios", strict_cast<double>(page_read_ios)); |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 303 | |
| 304 | return result; |
| 305 | } |
| 306 | |
| 307 | // Retrieves performance counters from the operating system. |
| 308 | // Fills in the provided |info| structure. Returns true on success. |
| 309 | BASE_EXPORT bool GetSystemPerformanceInfo(SystemPerformanceInfo* info) { |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 310 | SYSTEM_PERFORMANCE_INFORMATION counters = {}; |
Sebastien Marchand | 05183ceb | 2018-10-30 02:20:04 | [diff] [blame] | 311 | { |
| 312 | // The call to NtQuerySystemInformation might block on a lock. |
Etienne Bergeron | 436d4221 | 2019-02-26 17:15:12 | [diff] [blame] | 313 | base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, |
| 314 | BlockingType::MAY_BLOCK); |
Alex Gough | da69b90 | 2023-02-13 20:55:53 | [diff] [blame] | 315 | if (::NtQuerySystemInformation(::SystemPerformanceInformation, &counters, |
| 316 | sizeof(SYSTEM_PERFORMANCE_INFORMATION), |
| 317 | nullptr) != STATUS_SUCCESS) { |
Sebastien Marchand | 05183ceb | 2018-10-30 02:20:04 | [diff] [blame] | 318 | return false; |
| 319 | } |
| 320 | } |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 321 | |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 322 | info->idle_time = static_cast<uint64_t>(counters.IdleTime.QuadPart); |
| 323 | info->read_transfer_count = |
| 324 | static_cast<uint64_t>(counters.ReadTransferCount.QuadPart); |
| 325 | info->write_transfer_count = |
| 326 | static_cast<uint64_t>(counters.WriteTransferCount.QuadPart); |
| 327 | info->other_transfer_count = |
| 328 | static_cast<uint64_t>(counters.OtherTransferCount.QuadPart); |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 329 | info->read_operation_count = counters.ReadOperationCount; |
| 330 | info->write_operation_count = counters.WriteOperationCount; |
| 331 | info->other_operation_count = counters.OtherOperationCount; |
| 332 | info->pagefile_pages_written = counters.PagefilePagesWritten; |
| 333 | info->pagefile_pages_write_ios = counters.PagefilePageWriteIos; |
Sebastien Marchand | 57c036da | 2018-10-04 20:53:20 | [diff] [blame] | 334 | info->available_pages = counters.AvailablePages; |
| 335 | info->pages_read = counters.PagesRead; |
| 336 | info->page_read_ios = counters.PageReadIos; |
Etienne Bergeron | 0b9d2b6 | 2018-08-15 20:34:10 | [diff] [blame] | 337 | |
| 338 | return true; |
| 339 | } |
| 340 | |
[email protected] | 32f5e9a0 | 2013-05-23 12:59:54 | [diff] [blame] | 341 | } // namespace base |