Chromium Code Reviews| Index: components/startup_metric_utils/browser/startup_metric_utils.cc | 
| diff --git a/components/startup_metric_utils/browser/startup_metric_utils.cc b/components/startup_metric_utils/browser/startup_metric_utils.cc | 
| index 3949e6f3aaf53e5f0cedbc8cac070470285fe899..64e934f7674bf8ee5d9248f7710c4a21d1c16290 100644 | 
| --- a/components/startup_metric_utils/browser/startup_metric_utils.cc | 
| +++ b/components/startup_metric_utils/browser/startup_metric_utils.cc | 
| @@ -5,8 +5,10 @@ | 
| #include "components/startup_metric_utils/browser/startup_metric_utils.h" | 
| #include <stddef.h> | 
| +#include <stdint.h> | 
| #include <memory> | 
| +#include <string> | 
| #include "base/containers/hash_tables.h" | 
| #include "base/environment.h" | 
| @@ -28,7 +30,6 @@ | 
| #if defined(OS_WIN) | 
| #include <winternl.h> | 
| #include "base/win/win_util.h" | 
| -#include "base/win/windows_version.h" | 
| #endif | 
| namespace startup_metric_utils { | 
| @@ -54,6 +55,25 @@ base::LazyInstance<base::TimeTicks>::Leaky g_renderer_main_entry_point_ticks = | 
| base::LazyInstance<base::Time>::Leaky g_browser_main_entry_point_time = | 
| LAZY_INSTANCE_INITIALIZER; | 
| +// An enumeration of startup temperatures. This must be kept in sync with the | 
| +// UMA StartupType enumeration defined in histograms.xml. | 
| +enum StartupTemperature { | 
| + // The startup was a cold start: nearly all of the binaries and resources were | 
| + // brought into memory using hard faults. | 
| + COLD_STARTUP_TEMPERATURE = 0, | 
| + // The startup was a warm start: the binaries and resources were mostly | 
| + // already resident in memory and effectively no hard faults were observed. | 
| + WARM_STARTUP_TEMPERATURE = 1, | 
| + // The startup type couldn't quite be classified as warm or cold, but rather | 
| + // was somewhere in between. | 
| + LUKEWARM_STARTUP_TEMPERATURE = 2, | 
| + // This must be after all meaningful values. All new values should be added | 
| + // above this one. | 
| + STARTUP_TEMPERATURE_COUNT, | 
| + // Startup temperature wasn't yet determined. | 
| + UNDETERMINED_STARTUP_TEMPERATURE | 
| +}; | 
| + | 
| StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE; | 
| constexpr int kUndeterminedStartupsWithCurrentVersion = 0; | 
| @@ -70,11 +90,11 @@ int g_startups_with_current_version = kUndeterminedStartupsWithCurrentVersion; | 
| // Maximum number of hard faults tolerated for a startup to be classified as a | 
| // warm start. Set at roughly the 40th percentile of the HardFaultCount | 
| // histogram. | 
| -const uint32_t WARM_START_HARD_FAULT_COUNT_THRESHOLD = 5; | 
| +constexpr uint32_t kWarmStartHardFaultCountThreshold = 5; | 
| // Minimum number of hard faults expected for a startup to be classified as a | 
| // cold start. Set at roughly the 60th percentile of the HardFaultCount | 
| // histogram. | 
| -const uint32_t COLD_START_HARD_FAULT_COUNT_THRESHOLD = 1200; | 
| +constexpr uint32_t kColdStartHardFaultCountThreshold = 1200; | 
| // The struct used to return system process information via the NT internal | 
| // QuerySystemInformation call. This is partially documented at | 
| @@ -105,6 +125,61 @@ struct SYSTEM_PROCESS_INFORMATION_EX { | 
| // 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 through |hard_fault_count|. | 
| +// Returns true on success. | 
| +bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) { | 
| 
 
gab
2016/08/31 16:30:45
Assuming cut&paste as-is, not reviewing each line.
 
fdoray
2016/08/31 19:08:09
cut&paste + removed "if (base::win::GetVersion() <
 
 | 
| + DCHECK(hard_fault_count); | 
| + | 
| + // Get the function pointer. | 
| + static const 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; | 
| + const 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. | 
| + const 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 (base::win::HandleToUint32(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) | 
| #define UMA_HISTOGRAM_TIME_IN_MINUTES_MONTH_RANGE(name, sample) \ | 
| @@ -279,9 +354,9 @@ void RecordHardFaultHistogram() { | 
| // Determine the startup type based on the number of observed hard faults. | 
| DCHECK_EQ(UNDETERMINED_STARTUP_TEMPERATURE, g_startup_temperature); | 
| - if (hard_fault_count < WARM_START_HARD_FAULT_COUNT_THRESHOLD) { | 
| + if (hard_fault_count < kWarmStartHardFaultCountThreshold) { | 
| g_startup_temperature = WARM_STARTUP_TEMPERATURE; | 
| - } else if (hard_fault_count >= COLD_START_HARD_FAULT_COUNT_THRESHOLD) { | 
| + } else if (hard_fault_count >= kColdStartHardFaultCountThreshold) { | 
| g_startup_temperature = COLD_STARTUP_TEMPERATURE; | 
| } else { | 
| g_startup_temperature = LUKEWARM_STARTUP_TEMPERATURE; | 
| @@ -488,64 +563,6 @@ void RecordSameVersionStartupCount(PrefService* pref_service) { | 
| } // namespace | 
| -#if defined(OS_WIN) | 
| -bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) { | 
| - DCHECK(hard_fault_count); | 
| - | 
| - if (base::win::GetVersion() < base::win::VERSION_WIN7) | 
| - return false; | 
| - | 
| - // Get the function pointer. | 
| - static const 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 (base::win::HandleToUint32(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) | 
| - | 
| void RegisterPrefs(PrefRegistrySimple* registry) { | 
| DCHECK(registry); | 
| registry->RegisterInt64Pref(prefs::kLastStartupTimestamp, 0); | 
| @@ -771,8 +788,4 @@ base::TimeTicks MainEntryPointTicks() { | 
| return g_browser_main_entry_point_ticks.Get(); | 
| } | 
| -StartupTemperature GetStartupTemperature() { | 
| - return g_startup_temperature; | 
| -} | 
| - | 
| } // namespace startup_metric_utils |