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

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: Rebased and addressed nits. 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..b82da00fd0ccae419bfde47b2b76766cc6995ec9 100644
--- a/components/startup_metric_utils/startup_metric_utils.cc
+++ b/components/startup_metric_utils/startup_metric_utils.cc
@@ -16,6 +16,11 @@
#include "base/sys_info.h"
#include "base/time/time.h"
+#if defined(OS_WIN)
+#include <winternl.h>
+#include "base/win/windows_version.h"
+#endif
+
namespace {
// Mark as volatile to defensively make sure usage is thread-safe.
@@ -40,6 +45,151 @@ 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_t* hard_fault_count,
+ bool* has_os_support) {
+ DCHECK(hard_fault_count);
+ DCHECK(has_os_support);
+
+ if (base::win::GetVersion() < base::win::VERSION_WIN7) {
+ *has_os_support = false;
+ 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.
+ // NOTE: The actual required size depends entirely on the number of processes
+ // and threads running on the system. The initial guess suffices for
+ // ~100s of processes and ~1000s of threads.
+ std::vector<uint8_t> buffer(32 * 1024);
+ for (size_t tries = 0; tries < 3; ++tries) {
+ ULONG return_length = 0;
+ NTSTATUS status = query_sys_info(
+ SystemProcessInformation,
+ buffer.data(),
+ static_cast<ULONG>(buffer.size()),
+ &return_length);
+ // Insufficient space in the buffer.
+ if (return_length > buffer.size()) {
+ buffer.resize(return_length);
+ continue;
+ }
+ if (NT_SUCCESS(status) && return_length <= buffer.size())
+ break;
+ return false;
+ }
+
+ // Look for the struct housing information for the current process.
+ DWORD proc_id = ::GetCurrentProcessId();
+ size_t index = 0;
+ while (index < buffer.size()) {
+ DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), 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 when 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_t 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
+ // platforms.)
+ if (is_first_run) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Startup.BrowserMessageLoopStartHardFaultCount.FirstRun",
+ hard_fault_count,
+ 0, 40000, 50);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Startup.BrowserMessageLoopStartHardFaultCount",
+ hard_fault_count,
+ 0, 40000, 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 +265,7 @@ const base::Time MainEntryStartTime() {
}
void OnBrowserStartupComplete(bool is_first_run) {
+ RecordHardFaultHistogram(is_first_run);
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