• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors
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>  // Must be in front of other Windows header files.
8 
9 #include <psapi.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <winternl.h>
13 
14 #include <algorithm>
15 
16 #include "base/logging.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/notreached.h"
19 #include "base/process/process_metrics_iocounters.h"
20 #include "base/system/sys_info.h"
21 #include "base/threading/scoped_blocking_call.h"
22 #include "base/values.h"
23 #include "build/build_config.h"
24 
25 namespace base {
26 namespace {
27 
28 // ntstatus.h conflicts with windows.h so define this locally.
29 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
30 
31 // Definition of this struct is taken from the book:
32 // Windows NT/200, Native API reference, Gary Nebbett
33 struct SYSTEM_PERFORMANCE_INFORMATION {
34   // Total idle time of all processes in the system (units of 100 ns).
35   LARGE_INTEGER IdleTime;
36   // Number of bytes read (by all call to ZwReadFile).
37   LARGE_INTEGER ReadTransferCount;
38   // Number of bytes written (by all call to ZwWriteFile).
39   LARGE_INTEGER WriteTransferCount;
40   // Number of bytes transferred (e.g. DeviceIoControlFile)
41   LARGE_INTEGER OtherTransferCount;
42   // The amount of read operations.
43   ULONG ReadOperationCount;
44   // The amount of write operations.
45   ULONG WriteOperationCount;
46   // The amount of other operations.
47   ULONG OtherOperationCount;
48   // The number of pages of physical memory available to processes running on
49   // the system.
50   ULONG AvailablePages;
51   ULONG TotalCommittedPages;
52   ULONG TotalCommitLimit;
53   ULONG PeakCommitment;
54   ULONG PageFaults;
55   ULONG WriteCopyFaults;
56   ULONG TransitionFaults;
57   ULONG CacheTransitionFaults;
58   ULONG DemandZeroFaults;
59   // The number of pages read from disk to resolve page faults.
60   ULONG PagesRead;
61   // The number of read operations initiated to resolve page faults.
62   ULONG PageReadIos;
63   ULONG CacheReads;
64   ULONG CacheIos;
65   // The number of pages written to the system's pagefiles.
66   ULONG PagefilePagesWritten;
67   // The number of write operations performed on the system's pagefiles.
68   ULONG PagefilePageWriteIos;
69   ULONG MappedFilePagesWritten;
70   ULONG MappedFilePageWriteIos;
71   ULONG PagedPoolUsage;
72   ULONG NonPagedPoolUsage;
73   ULONG PagedPoolAllocs;
74   ULONG PagedPoolFrees;
75   ULONG NonPagedPoolAllocs;
76   ULONG NonPagedPoolFrees;
77   ULONG TotalFreeSystemPtes;
78   ULONG SystemCodePage;
79   ULONG TotalSystemDriverPages;
80   ULONG TotalSystemCodePages;
81   ULONG SmallNonPagedLookasideListAllocateHits;
82   ULONG SmallPagedLookasideListAllocateHits;
83   ULONG Reserved3;
84   ULONG MmSystemCachePage;
85   ULONG PagedPoolPage;
86   ULONG SystemDriverPage;
87   ULONG FastReadNoWait;
88   ULONG FastReadWait;
89   ULONG FastReadResourceMiss;
90   ULONG FastReadNotPossible;
91   ULONG FastMdlReadNoWait;
92   ULONG FastMdlReadWait;
93   ULONG FastMdlReadResourceMiss;
94   ULONG FastMdlReadNotPossible;
95   ULONG MapDataNoWait;
96   ULONG MapDataWait;
97   ULONG MapDataNoWaitMiss;
98   ULONG MapDataWaitMiss;
99   ULONG PinMappedDataCount;
100   ULONG PinReadNoWait;
101   ULONG PinReadWait;
102   ULONG PinReadNoWaitMiss;
103   ULONG PinReadWaitMiss;
104   ULONG CopyReadNoWait;
105   ULONG CopyReadWait;
106   ULONG CopyReadNoWaitMiss;
107   ULONG CopyReadWaitMiss;
108   ULONG MdlReadNoWait;
109   ULONG MdlReadWait;
110   ULONG MdlReadNoWaitMiss;
111   ULONG MdlReadWaitMiss;
112   ULONG ReadAheadIos;
113   ULONG LazyWriteIos;
114   ULONG LazyWritePages;
115   ULONG DataFlushes;
116   ULONG DataPages;
117   ULONG ContextSwitches;
118   ULONG FirstLevelTbFills;
119   ULONG SecondLevelTbFills;
120   ULONG SystemCalls;
121 };
122 
123 }  // namespace
124 
GetMaxFds()125 size_t GetMaxFds() {
126   // Windows is only limited by the amount of physical memory.
127   return std::numeric_limits<size_t>::max();
128 }
129 
GetHandleLimit()130 size_t GetHandleLimit() {
131   // Rounded down from value reported here:
132   // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
133   return static_cast<size_t>(1 << 23);
134 }
135 
136 // static
CreateProcessMetrics(ProcessHandle process)137 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
138     ProcessHandle process) {
139   return WrapUnique(new ProcessMetrics(process));
140 }
141 
GetCumulativeCPUUsage()142 TimeDelta ProcessMetrics::GetCumulativeCPUUsage() {
143   FILETIME creation_time;
144   FILETIME exit_time;
145   FILETIME kernel_time;
146   FILETIME user_time;
147 
148   if (!process_.is_valid())
149     return TimeDelta();
150 
151   if (!GetProcessTimes(process_.get(), &creation_time, &exit_time, &kernel_time,
152                        &user_time)) {
153     // This should never fail because we duplicate the handle to guarantee it
154     // will remain valid.
155     DCHECK(false);
156     return TimeDelta();
157   }
158 
159   return TimeDelta::FromFileTime(kernel_time) +
160          TimeDelta::FromFileTime(user_time);
161 }
162 
GetPreciseCumulativeCPUUsage()163 TimeDelta ProcessMetrics::GetPreciseCumulativeCPUUsage() {
164 #if defined(ARCH_CPU_ARM64)
165   // Precise CPU usage is not available on Arm CPUs because they don't support
166   // constant rate TSC.
167   return GetCumulativeCPUUsage();
168 #else   // !defined(ARCH_CPU_ARM64)
169   if (!time_internal::HasConstantRateTSC())
170     return GetCumulativeCPUUsage();
171 
172   const double tsc_ticks_per_second = time_internal::TSCTicksPerSecond();
173   if (tsc_ticks_per_second == 0) {
174     // TSC is only initialized once TSCTicksPerSecond() is called twice 50 ms
175     // apart on the same thread to get a baseline. This often doesn't happen in
176     // unit tests, and theoretically may happen in production if
177     // GetPreciseCumulativeCPUUsage() is called before any uses of ThreadTicks.
178     return GetCumulativeCPUUsage();
179   }
180 
181   ULONG64 process_cycle_time = 0;
182   if (!QueryProcessCycleTime(process_.get(), &process_cycle_time)) {
183     NOTREACHED();
184     return TimeDelta();
185   }
186 
187   const double process_time_seconds = process_cycle_time / tsc_ticks_per_second;
188   return Seconds(process_time_seconds);
189 #endif  // !defined(ARCH_CPU_ARM64)
190 }
191 
GetIOCounters(IoCounters * io_counters) const192 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
193   if (!process_.is_valid())
194     return false;
195 
196   return GetProcessIoCounters(process_.get(), io_counters) != FALSE;
197 }
198 
GetCumulativeDiskUsageInBytes()199 uint64_t ProcessMetrics::GetCumulativeDiskUsageInBytes() {
200   IoCounters counters;
201   if (!GetIOCounters(&counters))
202     return 0;
203 
204   return counters.ReadTransferCount + counters.WriteTransferCount +
205          counters.OtherTransferCount;
206 }
207 
ProcessMetrics(ProcessHandle process)208 ProcessMetrics::ProcessMetrics(ProcessHandle process) {
209   if (process) {
210     HANDLE duplicate_handle = INVALID_HANDLE_VALUE;
211     BOOL result = ::DuplicateHandle(::GetCurrentProcess(), process,
212                                     ::GetCurrentProcess(), &duplicate_handle,
213                                     PROCESS_QUERY_INFORMATION, FALSE, 0);
214     DPCHECK(result);
215     process_.Set(duplicate_handle);
216   }
217 }
218 
GetSystemCommitCharge()219 size_t GetSystemCommitCharge() {
220   // Get the System Page Size.
221   SYSTEM_INFO system_info;
222   GetSystemInfo(&system_info);
223 
224   PERFORMANCE_INFORMATION info;
225   if (!GetPerformanceInfo(&info, sizeof(info))) {
226     DLOG(ERROR) << "Failed to fetch internal performance info.";
227     return 0;
228   }
229   return (info.CommitTotal * system_info.dwPageSize) / 1024;
230 }
231 
232 // This function uses the following mapping between MEMORYSTATUSEX and
233 // SystemMemoryInfoKB:
234 //   ullTotalPhys ==> total
235 //   ullAvailPhys ==> avail_phys
236 //   ullTotalPageFile ==> swap_total
237 //   ullAvailPageFile ==> swap_free
GetSystemMemoryInfo(SystemMemoryInfoKB * meminfo)238 bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
239   MEMORYSTATUSEX mem_status;
240   mem_status.dwLength = sizeof(mem_status);
241   if (!::GlobalMemoryStatusEx(&mem_status))
242     return false;
243 
244   meminfo->total = saturated_cast<int>(mem_status.ullTotalPhys / 1024);
245   meminfo->avail_phys = saturated_cast<int>(mem_status.ullAvailPhys / 1024);
246   meminfo->swap_total = saturated_cast<int>(mem_status.ullTotalPageFile / 1024);
247   meminfo->swap_free = saturated_cast<int>(mem_status.ullAvailPageFile / 1024);
248 
249   return true;
250 }
251 
GetMallocUsage()252 size_t ProcessMetrics::GetMallocUsage() {
253   // Unsupported as getting malloc usage on Windows requires iterating through
254   // the heap which is slow and crashes.
255   return 0;
256 }
257 
258 SystemPerformanceInfo::SystemPerformanceInfo() = default;
259 SystemPerformanceInfo::SystemPerformanceInfo(
260     const SystemPerformanceInfo& other) = default;
261 SystemPerformanceInfo& SystemPerformanceInfo::operator=(
262     const SystemPerformanceInfo& other) = default;
263 
ToDict() const264 Value::Dict SystemPerformanceInfo::ToDict() const {
265   Value::Dict result;
266 
267   // Write out uint64_t variables as doubles.
268   // Note: this may discard some precision, but for JS there's no other option.
269   result.Set("idle_time", strict_cast<double>(idle_time));
270   result.Set("read_transfer_count", strict_cast<double>(read_transfer_count));
271   result.Set("write_transfer_count", strict_cast<double>(write_transfer_count));
272   result.Set("other_transfer_count", strict_cast<double>(other_transfer_count));
273   result.Set("read_operation_count", strict_cast<double>(read_operation_count));
274   result.Set("write_operation_count",
275              strict_cast<double>(write_operation_count));
276   result.Set("other_operation_count",
277              strict_cast<double>(other_operation_count));
278   result.Set("pagefile_pages_written",
279              strict_cast<double>(pagefile_pages_written));
280   result.Set("pagefile_pages_write_ios",
281              strict_cast<double>(pagefile_pages_write_ios));
282   result.Set("available_pages", strict_cast<double>(available_pages));
283   result.Set("pages_read", strict_cast<double>(pages_read));
284   result.Set("page_read_ios", strict_cast<double>(page_read_ios));
285 
286   return result;
287 }
288 
289 // Retrieves performance counters from the operating system.
290 // Fills in the provided |info| structure. Returns true on success.
GetSystemPerformanceInfo(SystemPerformanceInfo * info)291 BASE_EXPORT bool GetSystemPerformanceInfo(SystemPerformanceInfo* info) {
292   SYSTEM_PERFORMANCE_INFORMATION counters = {};
293   {
294     // The call to NtQuerySystemInformation might block on a lock.
295     base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
296                                                   BlockingType::MAY_BLOCK);
297     if (::NtQuerySystemInformation(::SystemPerformanceInformation, &counters,
298                                    sizeof(SYSTEM_PERFORMANCE_INFORMATION),
299                                    nullptr) != STATUS_SUCCESS) {
300       return false;
301     }
302   }
303 
304   info->idle_time = static_cast<uint64_t>(counters.IdleTime.QuadPart);
305   info->read_transfer_count =
306       static_cast<uint64_t>(counters.ReadTransferCount.QuadPart);
307   info->write_transfer_count =
308       static_cast<uint64_t>(counters.WriteTransferCount.QuadPart);
309   info->other_transfer_count =
310       static_cast<uint64_t>(counters.OtherTransferCount.QuadPart);
311   info->read_operation_count = counters.ReadOperationCount;
312   info->write_operation_count = counters.WriteOperationCount;
313   info->other_operation_count = counters.OtherOperationCount;
314   info->pagefile_pages_written = counters.PagefilePagesWritten;
315   info->pagefile_pages_write_ios = counters.PagefilePageWriteIos;
316   info->available_pages = counters.AvailablePages;
317   info->pages_read = counters.PagesRead;
318   info->page_read_ios = counters.PageReadIos;
319 
320   return true;
321 }
322 
323 }  // namespace base
324