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

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: 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..dd108fba2f132f2ebadeb04cbf9002ca1e299a0a 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,148 @@ base::Lock* GetSubsystemStartupTimeHashLock() {
return slow_startup_time_hash_lock;
}
+// 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
+struct SYSTEM_PROCESS_INFORMATION_EX {
+ ULONG NextEntryOffset;
+ ULONG NumberOfThreads;
+ LARGE_INTEGER WorkingSetPrivateSize;
+ ULONG HardFaultCount;
+ BYTE Reserved1[36];
+ PVOID Reserved2[3];
+ ULONG 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.
+};
+static_assert(
+ sizeof(SYSTEM_PROCESS_INFORMATION_EX) == 184,
Alexei Svitkine (slow) 2015/04/14 16:53:51 Is the size the same between 32 and 64 bit?
chrisha 2015/04/14 17:09:07 Good catch. Not the same size, but has the same la
+ "The definition of SYSTEM_PROCESS_INFORMATION_EX does not match the "
+ "expected size.");
+
+// 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)))
Alexei Svitkine (slow) 2015/04/14 16:53:51 Is this inside a file that's Windows-specific? If
+ 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 (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;
+}
+
+// On Windows, records the number of hard-faults that have occurred in the
+// current chrome.exe process since it was started.
+// crbug.com/476923
+// TODO(chrisha): If this proves useful, use it to split startup stats in two.
+void RecordHardFaultHistogram(bool is_first_run) {
+ 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
+ // 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",
+ hard_fault_count,
+ 0, 20000, 50);
+ }
+}
+
// 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 +261,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