- add sources.
[platform/framework/web/crosswalk.git] / src / components / startup_metric_utils / startup_metric_utils.cc
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.
4
5 #include "components/startup_metric_utils/startup_metric_utils.h"
6
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"
15
16 namespace {
17
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;
21
22 base::Time* MainEntryPointTimeInternal() {
23   static base::Time main_start_time = base::Time::Now();
24   return &main_start_time;
25 }
26
27 typedef base::hash_map<std::string,base::TimeDelta> SubsystemStartupTimeHash;
28
29 SubsystemStartupTimeHash* GetSubsystemStartupTimeHash() {
30   static SubsystemStartupTimeHash* slow_startup_time_hash =
31                                     new SubsystemStartupTimeHash;
32   return slow_startup_time_hash;
33 }
34
35 base::Lock* GetSubsystemStartupTimeHashLock() {
36   static base::Lock* slow_startup_time_hash_lock = new base::Lock;
37   return slow_startup_time_hash_lock;
38 }
39
40 bool g_main_entry_time_was_recorded = false;
41 bool g_startup_stats_collection_finished = false;
42 bool g_was_slow_startup = false;
43
44 }  // namespace
45
46 namespace startup_metric_utils {
47
48 bool WasNonBrowserUIDisplayed() {
49   return g_non_browser_ui_displayed;
50 }
51
52 void SetNonBrowserUIDisplayed() {
53   g_non_browser_ui_displayed = true;
54 }
55
56 void RecordMainEntryPointTime() {
57   DCHECK(!g_main_entry_time_was_recorded);
58   g_main_entry_time_was_recorded = true;
59   MainEntryPointTimeInternal();
60 }
61
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;
67 }
68 #endif // OS_ANDROID
69
70 // Return the time recorded by RecordMainEntryPointTime().
71 const base::Time MainEntryStartTime() {
72   DCHECK(g_main_entry_time_was_recorded);
73   return *MainEntryPointTimeInternal();
74 }
75
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;
83     return;
84   }
85
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
91   //   time.
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();
96   if (is_first_run) {
97     UMA_HISTOGRAM_LONG_TIMES(
98         "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun",
99         startup_time_from_main_entry);
100   } else {
101     UMA_HISTOGRAM_LONG_TIMES(
102         "Startup.BrowserMessageLoopStartTimeFromMainEntry",
103         startup_time_from_main_entry);
104   }
105
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;
110     return;
111   }
112
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;
116 }
117
118 void OnInitialPageLoadComplete() {
119   if (!g_was_slow_startup)
120     return;
121   DCHECK(!g_startup_stats_collection_finished);
122
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;
127
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");
132   if (histogram)
133     histogram->SetFlags(base::HistogramBase::kUmaTargetedHistogramFlag);
134
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();
141       ++i) {
142     const std::string histogram_name = i->first;
143     base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
144         histogram_name,
145         kStartupTimeMin,
146         kStartupTimeMax,
147         kStartupTimeBuckets,
148         base::Histogram::kUmaTargetedHistogramFlag);
149     counter->AddTime(i->second);
150   }
151
152   g_startup_stats_collection_finished = true;
153 }
154
155 ScopedSlowStartupUMA::~ScopedSlowStartupUMA() {
156   if (g_startup_stats_collection_finished)
157     return;
158
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())
163     return;
164
165   (*hash)[histogram_name_] =
166       base::TimeTicks::Now() - start_time_;
167 }
168
169 }  // namespace startup_metric_utils