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

Side by Side Diff: components/startup_metric_utils/browser/startup_metric_utils.cc

Issue 2283073002: Cleanup startup_metric_utils.h/.cc. (Closed)
Patch Set: Created 4 years, 3 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 unified diff | Download patch
« no previous file with comments | « components/startup_metric_utils/browser/startup_metric_utils.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/startup_metric_utils/browser/startup_metric_utils.h" 5 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h>
8 9
9 #include <memory> 10 #include <memory>
11 #include <string>
10 12
11 #include "base/containers/hash_tables.h" 13 #include "base/containers/hash_tables.h"
12 #include "base/environment.h" 14 #include "base/environment.h"
13 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
14 #include "base/logging.h" 16 #include "base/logging.h"
15 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
16 #include "base/metrics/histogram_macros.h" 18 #include "base/metrics/histogram_macros.h"
17 #include "base/process/process_info.h" 19 #include "base/process/process_info.h"
18 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_number_conversions.h"
19 #include "base/sys_info.h" 21 #include "base/sys_info.h"
20 #include "base/threading/platform_thread.h" 22 #include "base/threading/platform_thread.h"
21 #include "base/trace_event/trace_event.h" 23 #include "base/trace_event/trace_event.h"
22 #include "build/build_config.h" 24 #include "build/build_config.h"
23 #include "components/prefs/pref_registry_simple.h" 25 #include "components/prefs/pref_registry_simple.h"
24 #include "components/prefs/pref_service.h" 26 #include "components/prefs/pref_service.h"
25 #include "components/startup_metric_utils/browser/pref_names.h" 27 #include "components/startup_metric_utils/browser/pref_names.h"
26 #include "components/version_info/version_info.h" 28 #include "components/version_info/version_info.h"
27 29
28 #if defined(OS_WIN) 30 #if defined(OS_WIN)
29 #include <winternl.h> 31 #include <winternl.h>
30 #include "base/win/win_util.h" 32 #include "base/win/win_util.h"
31 #include "base/win/windows_version.h"
32 #endif 33 #endif
33 34
34 namespace startup_metric_utils { 35 namespace startup_metric_utils {
35 36
36 namespace { 37 namespace {
37 38
38 // Mark as volatile to defensively make sure usage is thread-safe. 39 // Mark as volatile to defensively make sure usage is thread-safe.
39 // Note that at the time of this writing, access is only on the UI thread. 40 // Note that at the time of this writing, access is only on the UI thread.
40 volatile bool g_non_browser_ui_displayed = false; 41 volatile bool g_non_browser_ui_displayed = false;
41 42
42 base::LazyInstance<base::TimeTicks>::Leaky g_process_creation_ticks = 43 base::LazyInstance<base::TimeTicks>::Leaky g_process_creation_ticks =
43 LAZY_INSTANCE_INITIALIZER; 44 LAZY_INSTANCE_INITIALIZER;
44 45
45 base::LazyInstance<base::TimeTicks>::Leaky g_browser_main_entry_point_ticks = 46 base::LazyInstance<base::TimeTicks>::Leaky g_browser_main_entry_point_ticks =
46 LAZY_INSTANCE_INITIALIZER; 47 LAZY_INSTANCE_INITIALIZER;
47 48
48 base::LazyInstance<base::TimeTicks>::Leaky g_renderer_main_entry_point_ticks = 49 base::LazyInstance<base::TimeTicks>::Leaky g_renderer_main_entry_point_ticks =
49 LAZY_INSTANCE_INITIALIZER; 50 LAZY_INSTANCE_INITIALIZER;
50 51
51 // Only used by RecordMainEntryTimeHistogram(), should go away with it (do not 52 // Only used by RecordMainEntryTimeHistogram(), should go away with it (do not
52 // add new uses of this), see crbug.com/317481 for discussion on why it was kept 53 // add new uses of this), see crbug.com/317481 for discussion on why it was kept
53 // as-is for now. 54 // as-is for now.
54 base::LazyInstance<base::Time>::Leaky g_browser_main_entry_point_time = 55 base::LazyInstance<base::Time>::Leaky g_browser_main_entry_point_time =
55 LAZY_INSTANCE_INITIALIZER; 56 LAZY_INSTANCE_INITIALIZER;
56 57
58 // An enumeration of startup temperatures. This must be kept in sync with the
59 // UMA StartupType enumeration defined in histograms.xml.
60 enum StartupTemperature {
61 // The startup was a cold start: nearly all of the binaries and resources were
62 // brought into memory using hard faults.
63 COLD_STARTUP_TEMPERATURE = 0,
64 // The startup was a warm start: the binaries and resources were mostly
65 // already resident in memory and effectively no hard faults were observed.
66 WARM_STARTUP_TEMPERATURE = 1,
67 // The startup type couldn't quite be classified as warm or cold, but rather
68 // was somewhere in between.
69 LUKEWARM_STARTUP_TEMPERATURE = 2,
70 // This must be after all meaningful values. All new values should be added
71 // above this one.
72 STARTUP_TEMPERATURE_COUNT,
73 // Startup temperature wasn't yet determined.
74 UNDETERMINED_STARTUP_TEMPERATURE
75 };
76
57 StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE; 77 StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE;
58 78
59 constexpr int kUndeterminedStartupsWithCurrentVersion = 0; 79 constexpr int kUndeterminedStartupsWithCurrentVersion = 0;
60 int g_startups_with_current_version = kUndeterminedStartupsWithCurrentVersion; 80 int g_startups_with_current_version = kUndeterminedStartupsWithCurrentVersion;
61 81
62 #if defined(OS_WIN) 82 #if defined(OS_WIN)
63 83
64 // These values are taken from the Startup.BrowserMessageLoopStartHardFaultCount 84 // These values are taken from the Startup.BrowserMessageLoopStartHardFaultCount
65 // histogram. If the cold start histogram starts looking strongly bimodal it may 85 // histogram. If the cold start histogram starts looking strongly bimodal it may
66 // be because the binary/resource sizes have grown significantly larger than 86 // be because the binary/resource sizes have grown significantly larger than
67 // when these values were set. In this case the new values need to be chosen 87 // when these values were set. In this case the new values need to be chosen
68 // from the original histogram. 88 // from the original histogram.
69 // 89 //
70 // Maximum number of hard faults tolerated for a startup to be classified as a 90 // Maximum number of hard faults tolerated for a startup to be classified as a
71 // warm start. Set at roughly the 40th percentile of the HardFaultCount 91 // warm start. Set at roughly the 40th percentile of the HardFaultCount
72 // histogram. 92 // histogram.
73 const uint32_t WARM_START_HARD_FAULT_COUNT_THRESHOLD = 5; 93 constexpr uint32_t kWarmStartHardFaultCountThreshold = 5;
74 // Minimum number of hard faults expected for a startup to be classified as a 94 // Minimum number of hard faults expected for a startup to be classified as a
75 // cold start. Set at roughly the 60th percentile of the HardFaultCount 95 // cold start. Set at roughly the 60th percentile of the HardFaultCount
76 // histogram. 96 // histogram.
77 const uint32_t COLD_START_HARD_FAULT_COUNT_THRESHOLD = 1200; 97 constexpr uint32_t kColdStartHardFaultCountThreshold = 1200;
78 98
79 // The struct used to return system process information via the NT internal 99 // The struct used to return system process information via the NT internal
80 // QuerySystemInformation call. This is partially documented at 100 // QuerySystemInformation call. This is partially documented at
81 // http://goo.gl/Ja9MrH and fully documented at http://goo.gl/QJ70rn 101 // http://goo.gl/Ja9MrH and fully documented at http://goo.gl/QJ70rn
82 // This structure is laid out in the same format on both 32-bit and 64-bit 102 // This structure is laid out in the same format on both 32-bit and 64-bit
83 // systems, but has a different size due to the various pointer-sized fields. 103 // systems, but has a different size due to the various pointer-sized fields.
84 struct SYSTEM_PROCESS_INFORMATION_EX { 104 struct SYSTEM_PROCESS_INFORMATION_EX {
85 ULONG NextEntryOffset; 105 ULONG NextEntryOffset;
86 ULONG NumberOfThreads; 106 ULONG NumberOfThreads;
87 LARGE_INTEGER WorkingSetPrivateSize; 107 LARGE_INTEGER WorkingSetPrivateSize;
(...skipping 10 matching lines...) Expand all
98 PVOID Reserved5[11]; 118 PVOID Reserved5[11];
99 SIZE_T PeakPagefileUsage; 119 SIZE_T PeakPagefileUsage;
100 SIZE_T PrivatePageCount; 120 SIZE_T PrivatePageCount;
101 LARGE_INTEGER Reserved6[6]; 121 LARGE_INTEGER Reserved6[6];
102 // Array of SYSTEM_THREAD_INFORMATION structs follows. 122 // Array of SYSTEM_THREAD_INFORMATION structs follows.
103 }; 123 };
104 124
105 // The signature of the NtQuerySystemInformation function. 125 // The signature of the NtQuerySystemInformation function.
106 typedef NTSTATUS (WINAPI *NtQuerySystemInformationPtr)( 126 typedef NTSTATUS (WINAPI *NtQuerySystemInformationPtr)(
107 SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); 127 SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
128
129 // Gets the hard fault count of the current process through |hard_fault_count|.
130 // Returns true on success.
131 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() <
132 DCHECK(hard_fault_count);
133
134 // Get the function pointer.
135 static const NtQuerySystemInformationPtr query_sys_info =
136 reinterpret_cast<NtQuerySystemInformationPtr>(::GetProcAddress(
137 GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"));
138 if (query_sys_info == nullptr)
139 return false;
140
141 // The output of this system call depends on the number of threads and
142 // processes on the entire system, and this can change between calls. Retry
143 // a small handful of times growing the buffer along the way.
144 // NOTE: The actual required size depends entirely on the number of processes
145 // and threads running on the system. The initial guess suffices for
146 // ~100s of processes and ~1000s of threads.
147 std::vector<uint8_t> buffer(32 * 1024);
148 for (size_t tries = 0; tries < 3; ++tries) {
149 ULONG return_length = 0;
150 const NTSTATUS status =
151 query_sys_info(SystemProcessInformation, buffer.data(),
152 static_cast<ULONG>(buffer.size()), &return_length);
153 // Insufficient space in the buffer.
154 if (return_length > buffer.size()) {
155 buffer.resize(return_length);
156 continue;
157 }
158 if (NT_SUCCESS(status) && return_length <= buffer.size())
159 break;
160 return false;
161 }
162
163 // Look for the struct housing information for the current process.
164 const DWORD proc_id = ::GetCurrentProcessId();
165 size_t index = 0;
166 while (index < buffer.size()) {
167 DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
168 SYSTEM_PROCESS_INFORMATION_EX* proc_info =
169 reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
170 if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
171 *hard_fault_count = proc_info->HardFaultCount;
172 return true;
173 }
174 // The list ends when NextEntryOffset is zero. This also prevents busy
175 // looping if the data is in fact invalid.
176 if (proc_info->NextEntryOffset <= 0)
177 return false;
178 index += proc_info->NextEntryOffset;
179 }
180
181 return false;
182 }
108 #endif // defined(OS_WIN) 183 #endif // defined(OS_WIN)
109 184
110 #define UMA_HISTOGRAM_TIME_IN_MINUTES_MONTH_RANGE(name, sample) \ 185 #define UMA_HISTOGRAM_TIME_IN_MINUTES_MONTH_RANGE(name, sample) \
111 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, \ 186 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, \
112 base::TimeDelta::FromDays(30).InMinutes(), 50) 187 base::TimeDelta::FromDays(30).InMinutes(), 50)
113 188
114 // Helper macro for splitting out an UMA histogram based on startup temperature. 189 // Helper macro for splitting out an UMA histogram based on startup temperature.
115 // |type| is the histogram type, and corresponds to an UMA macro like 190 // |type| is the histogram type, and corresponds to an UMA macro like
116 // UMA_HISTOGRAM_LONG_TIMES. It must itself be a macro that only takes two 191 // UMA_HISTOGRAM_LONG_TIMES. It must itself be a macro that only takes two
117 // parameters. 192 // parameters.
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 // Factory properties copied from UMA_HISTOGRAM_CUSTOM_COUNTS macro. 347 // Factory properties copied from UMA_HISTOGRAM_CUSTOM_COUNTS macro.
273 if (!same_version_startup_count_suffix.empty()) { 348 if (!same_version_startup_count_suffix.empty()) {
274 base::Histogram::FactoryGet( 349 base::Histogram::FactoryGet(
275 kHardFaultCountHistogram + same_version_startup_count_suffix, 1, 40000, 350 kHardFaultCountHistogram + same_version_startup_count_suffix, 1, 40000,
276 50, base::HistogramBase::kUmaTargetedHistogramFlag) 351 50, base::HistogramBase::kUmaTargetedHistogramFlag)
277 ->Add(hard_fault_count); 352 ->Add(hard_fault_count);
278 } 353 }
279 354
280 // Determine the startup type based on the number of observed hard faults. 355 // Determine the startup type based on the number of observed hard faults.
281 DCHECK_EQ(UNDETERMINED_STARTUP_TEMPERATURE, g_startup_temperature); 356 DCHECK_EQ(UNDETERMINED_STARTUP_TEMPERATURE, g_startup_temperature);
282 if (hard_fault_count < WARM_START_HARD_FAULT_COUNT_THRESHOLD) { 357 if (hard_fault_count < kWarmStartHardFaultCountThreshold) {
283 g_startup_temperature = WARM_STARTUP_TEMPERATURE; 358 g_startup_temperature = WARM_STARTUP_TEMPERATURE;
284 } else if (hard_fault_count >= COLD_START_HARD_FAULT_COUNT_THRESHOLD) { 359 } else if (hard_fault_count >= kColdStartHardFaultCountThreshold) {
285 g_startup_temperature = COLD_STARTUP_TEMPERATURE; 360 g_startup_temperature = COLD_STARTUP_TEMPERATURE;
286 } else { 361 } else {
287 g_startup_temperature = LUKEWARM_STARTUP_TEMPERATURE; 362 g_startup_temperature = LUKEWARM_STARTUP_TEMPERATURE;
288 } 363 }
289 364
290 // Record the startup 'temperature'. 365 // Record the startup 'temperature'.
291 const char kStartupTemperatureHistogram[] = "Startup.Temperature"; 366 const char kStartupTemperatureHistogram[] = "Startup.Temperature";
292 UMA_HISTOGRAM_ENUMERATION(kStartupTemperatureHistogram, g_startup_temperature, 367 UMA_HISTOGRAM_ENUMERATION(kStartupTemperatureHistogram, g_startup_temperature,
293 STARTUP_TEMPERATURE_COUNT); 368 STARTUP_TEMPERATURE_COUNT);
294 // As well as its suffixed twin. 369 // As well as its suffixed twin.
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 pref_service->SetString(prefs::kLastStartupVersion, current_version); 556 pref_service->SetString(prefs::kLastStartupVersion, current_version);
482 pref_service->SetInteger(prefs::kSameVersionStartupCount, 1); 557 pref_service->SetInteger(prefs::kSameVersionStartupCount, 1);
483 } 558 }
484 559
485 UMA_HISTOGRAM_COUNTS_100("Startup.SameVersionStartupCount", 560 UMA_HISTOGRAM_COUNTS_100("Startup.SameVersionStartupCount",
486 g_startups_with_current_version); 561 g_startups_with_current_version);
487 } 562 }
488 563
489 } // namespace 564 } // namespace
490 565
491 #if defined(OS_WIN)
492 bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) {
493 DCHECK(hard_fault_count);
494
495 if (base::win::GetVersion() < base::win::VERSION_WIN7)
496 return false;
497
498 // Get the function pointer.
499 static const NtQuerySystemInformationPtr query_sys_info =
500 reinterpret_cast<NtQuerySystemInformationPtr>(::GetProcAddress(
501 GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"));
502 if (query_sys_info == nullptr)
503 return false;
504
505 // The output of this system call depends on the number of threads and
506 // processes on the entire system, and this can change between calls. Retry
507 // a small handful of times growing the buffer along the way.
508 // NOTE: The actual required size depends entirely on the number of processes
509 // and threads running on the system. The initial guess suffices for
510 // ~100s of processes and ~1000s of threads.
511 std::vector<uint8_t> buffer(32 * 1024);
512 for (size_t tries = 0; tries < 3; ++tries) {
513 ULONG return_length = 0;
514 NTSTATUS status =
515 query_sys_info(SystemProcessInformation, buffer.data(),
516 static_cast<ULONG>(buffer.size()), &return_length);
517 // Insufficient space in the buffer.
518 if (return_length > buffer.size()) {
519 buffer.resize(return_length);
520 continue;
521 }
522 if (NT_SUCCESS(status) && return_length <= buffer.size())
523 break;
524 return false;
525 }
526
527 // Look for the struct housing information for the current process.
528 DWORD proc_id = ::GetCurrentProcessId();
529 size_t index = 0;
530 while (index < buffer.size()) {
531 DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
532 SYSTEM_PROCESS_INFORMATION_EX* proc_info =
533 reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
534 if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
535 *hard_fault_count = proc_info->HardFaultCount;
536 return true;
537 }
538 // The list ends when NextEntryOffset is zero. This also prevents busy
539 // looping if the data is in fact invalid.
540 if (proc_info->NextEntryOffset <= 0)
541 return false;
542 index += proc_info->NextEntryOffset;
543 }
544
545 return false;
546 }
547 #endif // defined(OS_WIN)
548
549 void RegisterPrefs(PrefRegistrySimple* registry) { 566 void RegisterPrefs(PrefRegistrySimple* registry) {
550 DCHECK(registry); 567 DCHECK(registry);
551 registry->RegisterInt64Pref(prefs::kLastStartupTimestamp, 0); 568 registry->RegisterInt64Pref(prefs::kLastStartupTimestamp, 0);
552 registry->RegisterStringPref(prefs::kLastStartupVersion, std::string()); 569 registry->RegisterStringPref(prefs::kLastStartupVersion, std::string());
553 registry->RegisterIntegerPref(prefs::kSameVersionStartupCount, 0); 570 registry->RegisterIntegerPref(prefs::kSameVersionStartupCount, 0);
554 } 571 }
555 572
556 bool WasNonBrowserUIDisplayed() { 573 bool WasNonBrowserUIDisplayed() {
557 return g_non_browser_ui_displayed; 574 return g_non_browser_ui_displayed;
558 } 575 }
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
764 UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( 781 UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
765 UMA_HISTOGRAM_LONG_TIMES_100, 782 UMA_HISTOGRAM_LONG_TIMES_100,
766 "Startup.FirstWebContents.MainNavigationFinished", 783 "Startup.FirstWebContents.MainNavigationFinished",
767 g_process_creation_ticks.Get(), ticks); 784 g_process_creation_ticks.Get(), ticks);
768 } 785 }
769 786
770 base::TimeTicks MainEntryPointTicks() { 787 base::TimeTicks MainEntryPointTicks() {
771 return g_browser_main_entry_point_ticks.Get(); 788 return g_browser_main_entry_point_ticks.Get();
772 } 789 }
773 790
774 StartupTemperature GetStartupTemperature() {
775 return g_startup_temperature;
776 }
777
778 } // namespace startup_metric_utils 791 } // namespace startup_metric_utils
OLDNEW
« no previous file with comments | « components/startup_metric_utils/browser/startup_metric_utils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698