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
3 // found in the LICENSE file.
5 #include "components/startup_metric_utils/startup_metric_utils.h"
7 #include "base/containers/hash_tables.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/histogram_base.h"
11 #include "base/metrics/statistics_recorder.h"
12 #include "base/synchronization/lock.h"
13 #include "base/sys_info.h"
14 #include "base/time/time.h"
18 // Mark as volatile to defensively make sure usage is thread-safe.
19 // Note that at the time of this writing, access is only on the UI thread.
20 volatile bool g_non_browser_ui_displayed
= false;
22 base::Time
* MainEntryPointTimeInternal() {
23 static base::Time main_start_time
= base::Time::Now();
24 return &main_start_time
;
27 typedef base::hash_map
<std::string
,base::TimeDelta
> SubsystemStartupTimeHash
;
29 SubsystemStartupTimeHash
* GetSubsystemStartupTimeHash() {
30 static SubsystemStartupTimeHash
* slow_startup_time_hash
=
31 new SubsystemStartupTimeHash
;
32 return slow_startup_time_hash
;
35 base::Lock
* GetSubsystemStartupTimeHashLock() {
36 static base::Lock
* slow_startup_time_hash_lock
= new base::Lock
;
37 return slow_startup_time_hash_lock
;
40 bool g_main_entry_time_was_recorded
= false;
41 bool g_startup_stats_collection_finished
= false;
42 bool g_was_slow_startup
= false;
46 namespace startup_metric_utils
{
48 bool WasNonBrowserUIDisplayed() {
49 return g_non_browser_ui_displayed
;
52 void SetNonBrowserUIDisplayed() {
53 g_non_browser_ui_displayed
= true;
56 void RecordMainEntryPointTime() {
57 DCHECK(!g_main_entry_time_was_recorded
);
58 g_main_entry_time_was_recorded
= true;
59 MainEntryPointTimeInternal();
62 #if defined(OS_ANDROID)
63 void RecordSavedMainEntryPointTime(const base::Time
& entry_point_time
) {
64 DCHECK(!g_main_entry_time_was_recorded
);
65 g_main_entry_time_was_recorded
= true;
66 *MainEntryPointTimeInternal() = entry_point_time
;
70 // Return the time recorded by RecordMainEntryPointTime().
71 const base::Time
MainEntryStartTime() {
72 DCHECK(g_main_entry_time_was_recorded
);
73 return *MainEntryPointTimeInternal();
76 void OnBrowserStartupComplete(bool is_first_run
) {
77 // Bail if uptime < 7 minutes, to filter out cases where Chrome may have been
78 // autostarted and the machine is under io pressure.
79 const int64 kSevenMinutesInMilliseconds
=
80 base::TimeDelta::FromMinutes(7).InMilliseconds();
81 if (base::SysInfo::Uptime() < kSevenMinutesInMilliseconds
) {
82 g_startup_stats_collection_finished
= true;
86 // The Startup.BrowserMessageLoopStartTime histogram recorded in
87 // chrome_browser_main.cc exhibits instability in the field which limits its
88 // usefulness in all scenarios except when we have a very large sample size.
89 // Attempt to mitigate this with a new metric:
90 // * Measure time from main entry rather than the OS' notion of process start
92 // * Only measure launches that occur 7 minutes after boot to try to avoid
93 // cases where Chrome is auto-started and IO is heavily loaded.
94 base::TimeDelta startup_time_from_main_entry
=
95 base::Time::Now() - MainEntryStartTime();
97 UMA_HISTOGRAM_LONG_TIMES(
98 "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun",
99 startup_time_from_main_entry
);
101 UMA_HISTOGRAM_LONG_TIMES(
102 "Startup.BrowserMessageLoopStartTimeFromMainEntry",
103 startup_time_from_main_entry
);
106 // Record histograms for the subsystem times for startups > 10 seconds.
107 const base::TimeDelta kTenSeconds
= base::TimeDelta::FromSeconds(10);
108 if (startup_time_from_main_entry
< kTenSeconds
) {
109 g_startup_stats_collection_finished
= true;
113 // If we got here this was what we consider to be a slow startup which we
114 // want to record stats for.
115 g_was_slow_startup
= true;
118 void OnInitialPageLoadComplete() {
119 if (!g_was_slow_startup
)
121 DCHECK(!g_startup_stats_collection_finished
);
123 const base::TimeDelta
kStartupTimeMin(
124 base::TimeDelta::FromMilliseconds(1));
125 const base::TimeDelta
kStartupTimeMax(base::TimeDelta::FromMinutes(5));
126 static const size_t kStartupTimeBuckets
= 100;
128 // Set UMA flag for histograms outside chrome/ that can't use the
129 // ScopedSlowStartupUMA class.
130 base::HistogramBase
* histogram
=
131 base::StatisticsRecorder::FindHistogram("Startup.SlowStartupNSSInit");
133 histogram
->SetFlags(base::HistogramBase::kUmaTargetedHistogramFlag
);
135 // Iterate over the stats recorded by ScopedSlowStartupUMA and create
136 // histograms for them.
137 base::AutoLock
locker(*GetSubsystemStartupTimeHashLock());
138 SubsystemStartupTimeHash
* time_hash
= GetSubsystemStartupTimeHash();
139 for (SubsystemStartupTimeHash::iterator i
= time_hash
->begin();
140 i
!= time_hash
->end();
142 const std::string histogram_name
= i
->first
;
143 base::HistogramBase
* counter
= base::Histogram::FactoryTimeGet(
148 base::Histogram::kUmaTargetedHistogramFlag
);
149 counter
->AddTime(i
->second
);
152 g_startup_stats_collection_finished
= true;
155 ScopedSlowStartupUMA::~ScopedSlowStartupUMA() {
156 if (g_startup_stats_collection_finished
)
159 base::AutoLock
locker(*GetSubsystemStartupTimeHashLock());
160 SubsystemStartupTimeHash
* hash
= GetSubsystemStartupTimeHash();
161 // Only record the initial sample for a given histogram.
162 if (hash
->find(histogram_name_
) != hash
->end())
165 (*hash
)[histogram_name_
] =
166 base::TimeTicks::Now() - start_time_
;
169 } // namespace startup_metric_utils