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

Unified Diff: components/startup_metric_utils/startup_metric_utils.cc

Issue 1084943002: Add UMA stats for hard-fault counts for Windows 7 and greater. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix for non Win32 platforms. Created 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/startup_metric_utils/startup_metric_utils.cc
diff --git a/components/startup_metric_utils/startup_metric_utils.cc b/components/startup_metric_utils/startup_metric_utils.cc
index 642a0c488823b675c2468a2098e0277227823212..d76cc0e858a78804b9abbb396f8e7ef26820f21e 100644
--- a/components/startup_metric_utils/startup_metric_utils.cc
+++ b/components/startup_metric_utils/startup_metric_utils.cc
@@ -16,6 +16,10 @@
#include "base/sys_info.h"
#include "base/time/time.h"
+#if defined(OS_WIN)
+#include <winternl.h>
+#endif
+
namespace {
// Mark as volatile to defensively make sure usage is thread-safe.
@@ -40,6 +44,156 @@ base::Lock* GetSubsystemStartupTimeHashLock() {
return slow_startup_time_hash_lock;
}
+#if defined(OS_WIN)
+
+// The struct used to return system process information via the NT internal
+// QuerySystemInformation call. This is partially documented at
+// http://goo.gl/Ja9MrH and fully documented at http://goo.gl/QJ70rn
+// This structure is laid out in the same format on both 32-bit and 64-bit
+// systems, but has a different size due to the various pointer sized fields.
+struct SYSTEM_PROCESS_INFORMATION_EX {
+ ULONG NextEntryOffset;
+ ULONG NumberOfThreads;
+ LARGE_INTEGER WorkingSetPrivateSize;
+ ULONG HardFaultCount;
+ BYTE Reserved1[36];
+ PVOID Reserved2[3];
+ // This is labeled a handle so that it expands to the correct size for 32-bit
+ // and 64-bit operating systems. However, under the hood it's a 32-bit DWORD
+ // containing the process ID.
+ HANDLE UniqueProcessId;
+ PVOID Reserved3;
+ ULONG HandleCount;
+ BYTE Reserved4[4];
+ PVOID Reserved5[11];
+ SIZE_T PeakPagefileUsage;
+ SIZE_T PrivatePageCount;
+ LARGE_INTEGER Reserved6[6];
+ // Array of SYSTEM_THREAD_INFORMATION structs follows.
+};
+
+// The signature of the NtQuerySystemInformation function.
+typedef NTSTATUS (WINAPI *NtQuerySystemInformationPtr)(
+ SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+
+// Gets the hard fault count of the current process, returning it via
+// |hard_fault_count|. Returns true on success, false otherwise. Also returns
+// whether or not the system call was even possible for the current OS version
+// via |has_os_support|.
+bool GetHardFaultCountForCurrentProcess(uint32* hard_fault_count,
+ bool* has_os_support) {
+ DCHECK(hard_fault_count);
+ DCHECK(has_os_support);
+
+ *has_os_support = false;
+ OSVERSIONINFOEX version_info = {};
+ version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if (!::GetVersionEx(reinterpret_cast<LPOSVERSIONINFOW>(&version_info)))
+ return false;
+
+ // The hard fault counter is only available as of Windows 7 (version 6.1).
+ if (version_info.dwMajorVersion < 6)
+ return false;
+ if (version_info.dwMajorVersion == 6 && version_info.dwMinorVersion < 1)
+ return false;
+
+ // At this point the OS supports the required system call.
+ *has_os_support = true;
+
+ // Get the function pointer.
+ NtQuerySystemInformationPtr query_sys_info =
+ reinterpret_cast<NtQuerySystemInformationPtr>(
+ ::GetProcAddress(GetModuleHandle(L"ntdll.dll"),
+ "NtQuerySystemInformation"));
+ if (query_sys_info == nullptr)
+ return false;
+
+ // The output of this system call depends on the number of threads and
+ // processes on the entire system, and this can change between calls. Retry
+ // a small handful of times growing the buffer along the way.
+ std::vector<uint8> buffer(1024);
+ for (size_t tries = 0; tries < 3; ++tries) {
+ ULONG return_length = 0;
+ NTSTATUS status = query_sys_info(
+ SystemProcessInformation,
+ buffer.data(),
+ buffer.size(),
+ &return_length);
+ // Insufficient space in the buffer.
+ if (return_length > buffer.size()) {
+ buffer.resize(return_length);
+ continue;
+ }
+ if (status == 0 && return_length <= buffer.size())
+ break;
+ return false;
+ }
+ // The only way out to get here is if the system call was successful.
+
+ // Look for the struct housing information for the current process.
+ DWORD proc_id = ::GetCurrentProcessId();
+ size_t index = 0;
+ while (index < buffer.size()) {
+ SYSTEM_PROCESS_INFORMATION_EX* proc_info =
+ reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
+ if (reinterpret_cast<DWORD>(proc_info->UniqueProcessId) == proc_id) {
+ *hard_fault_count = proc_info->HardFaultCount;
+ return true;
+ }
+ // The list ends with NextEntryOffset is zero. This also prevents busy
+ // looping if the data is in fact invalid.
+ if (proc_info->NextEntryOffset == 0)
+ return false;
+ index += proc_info->NextEntryOffset;
+ }
+
+ return false;
+}
+
+#endif // defined(OS_WIN)
+
+// On Windows, records the number of hard-faults that have occurred in the
+// current chrome.exe process since it was started. This is a nop on other
+// platforms.
+// crbug.com/476923
+// TODO(chrisha): If this proves useful, use it to split startup stats in two.
+void RecordHardFaultHistogram(bool is_first_run) {
+#if defined(OS_WIN)
+ uint32 hard_fault_count = 0;
+ bool has_os_support = false;
+ bool success = GetHardFaultCountForCurrentProcess(
+ &hard_fault_count, &has_os_support);
+
+ // Log whether or not the system call was successful, assuming the OS was
+ // detected to support it.
+ if (has_os_support) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Startup.BrowserMessageLoopStartHardFaultCount.Success",
+ success);
+ }
+
+ // Don't log a histogram value if unable to get the hard fault count.
+ if (!success)
+ return;
+
+ // Hard fault counts are expected to be in the thousands range,
+ // corresponding to faulting in ~10s of MBs of code ~10s of KBs at a time.
+ // (Observed to vary from 1000 to 10000 on various test machines and
erikchen 2015/04/14 23:01:52 If you're observing 10000 on a test machine, it's
chrisha 2015/04/15 13:04:30 I suppose it could go drastically higher, but it w
erikchen 2015/04/15 17:26:59 Sounds reasonable to me. We can always change the
+ // platforms.)
+ if (is_first_run) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Startup.BrowserMessageLoopStartHardFaultCount.FirstRun",
+ hard_fault_count,
+ 0, 20000, 50);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Startup.BrowserMessageLoopStartHardFaultCount",
erikchen 2015/04/14 23:01:52 The description you give for this metric implies i
chrisha 2015/04/15 13:04:29 I was just being consistent with how Startup.Brows
+ hard_fault_count,
+ 0, 20000, 50);
+ }
+#endif // defined(OS_WIN)
+}
+
// Record time of main entry so it can be read from Telemetry performance
// tests.
// TODO(jeremy): Remove once crbug.com/317481 is fixed.
@@ -115,6 +269,7 @@ const base::Time MainEntryStartTime() {
}
void OnBrowserStartupComplete(bool is_first_run) {
+ RecordHardFaultHistogram(is_first_run);
erikchen 2015/04/14 23:01:52 As a quick sanity check, can you confirm that this
chrisha 2015/04/15 13:04:30 This was benchmarked across various versions of th
RecordMainEntryTimeHistogram();
// Bail if uptime < 7 minutes, to filter out cases where Chrome may have been
« no previous file with comments | « no previous file | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698