Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2012 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 "chrome/common/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 const 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 // Return the time recorded by RecordMainEntryPointTime().
     63 const base::Time MainEntryStartTime() {
     64   DCHECK(g_main_entry_time_was_recorded);
     65   return *MainEntryPointTimeInternal();
     66 }
     67 
     68 void OnBrowserStartupComplete(bool is_first_run) {
     69   // Bail if uptime < 7 minutes, to filter out cases where Chrome may have been
     70   // autostarted and the machine is under io pressure.
     71   const int64 kSevenMinutesInMilliseconds =
     72       base::TimeDelta::FromMinutes(7).InMilliseconds();
     73   if (base::SysInfo::Uptime() < kSevenMinutesInMilliseconds) {
     74     g_startup_stats_collection_finished = true;
     75     return;
     76   }
     77 
     78   // The Startup.BrowserMessageLoopStartTime histogram recorded in
     79   // chrome_browser_main.cc exhibits instability in the field which limits its
     80   // usefulness in all scenarios except when we have a very large sample size.
     81   // Attempt to mitigate this with a new metric:
     82   // * Measure time from main entry rather than the OS' notion of process start
     83   //   time.
     84   // * Only measure launches that occur 7 minutes after boot to try to avoid
     85   //   cases where Chrome is auto-started and IO is heavily loaded.
     86   base::TimeDelta startup_time_from_main_entry =
     87       base::Time::Now() - MainEntryStartTime();
     88   if (is_first_run) {
     89     UMA_HISTOGRAM_LONG_TIMES(
     90         "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun",
     91         startup_time_from_main_entry);
     92   } else {
     93     UMA_HISTOGRAM_LONG_TIMES(
     94         "Startup.BrowserMessageLoopStartTimeFromMainEntry",
     95         startup_time_from_main_entry);
     96   }
     97 
     98   // Record histograms for the subsystem times for startups > 10 seconds.
     99   const base::TimeDelta kTenSeconds = base::TimeDelta::FromSeconds(10);
    100   if (startup_time_from_main_entry < kTenSeconds) {
    101     g_startup_stats_collection_finished = true;
    102     return;
    103   }
    104 
    105   // If we got here this was what we consider to be a slow startup which we
    106   // want to record stats for.
    107   g_was_slow_startup = true;
    108 }
    109 
    110 void OnInitialPageLoadComplete() {
    111   if (!g_was_slow_startup)
    112     return;
    113   DCHECK(!g_startup_stats_collection_finished);
    114 
    115   const base::TimeDelta kStartupTimeMin(
    116       base::TimeDelta::FromMilliseconds(1));
    117   const base::TimeDelta kStartupTimeMax(base::TimeDelta::FromMinutes(5));
    118   static const size_t kStartupTimeBuckets = 100;
    119 
    120   // Set UMA flag for histograms outside chrome/ that can't use the
    121   // ScopedSlowStartupUMA class.
    122   base::HistogramBase* histogram =
    123       base::StatisticsRecorder::FindHistogram("Startup.SlowStartupNSSInit");
    124   if (histogram)
    125     histogram->SetFlags(base::HistogramBase::kUmaTargetedHistogramFlag);
    126 
    127   // Iterate over the stats recorded by ScopedSlowStartupUMA and create
    128   // histograms for them.
    129   base::AutoLock locker(*GetSubsystemStartupTimeHashLock());
    130   SubsystemStartupTimeHash* time_hash = GetSubsystemStartupTimeHash();
    131   for (SubsystemStartupTimeHash::iterator i = time_hash->begin();
    132       i != time_hash->end();
    133       ++i) {
    134     const std::string histogram_name = i->first;
    135     base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
    136         histogram_name,
    137         kStartupTimeMin,
    138         kStartupTimeMax,
    139         kStartupTimeBuckets,
    140         base::Histogram::kUmaTargetedHistogramFlag);
    141     counter->AddTime(i->second);
    142   }
    143 
    144   g_startup_stats_collection_finished = true;
    145 }
    146 
    147 ScopedSlowStartupUMA::~ScopedSlowStartupUMA() {
    148   if (g_startup_stats_collection_finished)
    149     return;
    150 
    151   base::AutoLock locker(*GetSubsystemStartupTimeHashLock());
    152   SubsystemStartupTimeHash* hash = GetSubsystemStartupTimeHash();
    153   // Only record the initial sample for a given histogram.
    154   if (hash->find(histogram_name_) !=  hash->end())
    155     return;
    156 
    157   (*hash)[histogram_name_] =
    158       base::TimeTicks::Now() - start_time_;
    159 }
    160 
    161 }  // namespace startup_metric_utils
    162