perf_provider_chromeos.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
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 <string> 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/callback.h" 10#include "base/command_line.h" 11#include "base/compiler_specific.h" 12#include "base/metrics/histogram.h" 13#include "base/rand_util.h" 14#include "base/strings/string_number_conversions.h" 15#include "base/threading/sequenced_worker_pool.h" 16#include "chrome/browser/metrics/perf_provider_chromeos.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/browser/ui/browser.h" 19#include "chrome/browser/ui/browser_list.h" 20#include "chrome/browser/ui/browser_list_observer.h" 21#include "chrome/common/chrome_switches.h" 22#include "chromeos/dbus/dbus_thread_manager.h" 23#include "chromeos/dbus/debug_daemon_client.h" 24#include "content/public/browser/browser_thread.h" 25 26namespace { 27 28// Default time in seconds between invocations of perf. 29// This period is roughly 6.5 hours. 30// This is chosen to be relatively prime with the number of seconds in: 31// - one minute (60) 32// - one hour (3600) 33// - one day (86400) 34const size_t kPerfCommandIntervalDefaultSeconds = 23093; 35 36// The first collection interval is different from the interval above. This is 37// because we want to collect the first profile quickly after Chrome is started. 38// If this period is too long, the user will log off and Chrome will be killed 39// before it is triggered. The following 2 variables determine the upper and 40// lower bound on the interval. 41// The reason we do not always want to collect the initial profile after a fixed 42// period is to not over-represent task X in the profile where task X always 43// runs at a fixed period after start-up. By selecting a period randomly between 44// a lower and upper bound, we will hopefully collect a more fair profile. 45const size_t kPerfCommandStartIntervalLowerBoundMinutes = 10; 46 47const size_t kPerfCommandStartIntervalUpperBoundMinutes = 20; 48 49const size_t kNumberOfSecondsInAMinute = 60; 50 51// Default time in seconds perf is run for. 52const size_t kPerfCommandDurationDefaultSeconds = 2; 53 54// Enumeration representing success and various failure modes for collecting and 55// sending perf data. 56enum GetPerfDataOutcome { 57 SUCCESS, 58 NOT_READY_TO_UPLOAD, 59 NOT_READY_TO_COLLECT, 60 INCOGNITO_ACTIVE, 61 INCOGNITO_LAUNCHED, 62 PROTOBUF_NOT_PARSED, 63 NUM_OUTCOMES 64}; 65 66// Name of the histogram that represents the success and various failure modes 67// for collecting and sending perf data. 68const char kGetPerfDataOutcomeHistogram[] = "UMA.Perf.GetData"; 69 70void AddToPerfHistogram(GetPerfDataOutcome outcome) { 71 UMA_HISTOGRAM_ENUMERATION(kGetPerfDataOutcomeHistogram, 72 outcome, 73 NUM_OUTCOMES); 74} 75 76} // namespace 77 78 79namespace metrics { 80 81// This class must be created and used on the UI thread. It watches for any 82// incognito window being opened from the time it is instantiated to the time it 83// is destroyed. 84class WindowedIncognitoObserver : public chrome::BrowserListObserver { 85 public: 86 WindowedIncognitoObserver() : incognito_launched_(false) { 87 BrowserList::AddObserver(this); 88 } 89 90 virtual ~WindowedIncognitoObserver() { 91 BrowserList::RemoveObserver(this); 92 } 93 94 // This method can be checked to see whether any incognito window has been 95 // opened since the time this object was created. 96 bool incognito_launched() { 97 return incognito_launched_; 98 } 99 100 private: 101 // chrome::BrowserListObserver implementation. 102 virtual void OnBrowserAdded(Browser* browser) OVERRIDE { 103 if (browser->profile()->IsOffTheRecord()) 104 incognito_launched_ = true; 105 } 106 107 bool incognito_launched_; 108}; 109 110PerfProvider::PerfProvider() 111 : state_(READY_TO_COLLECT), 112 weak_factory_(this) { 113 size_t collection_interval_minutes = base::RandInt( 114 kPerfCommandStartIntervalLowerBoundMinutes, 115 kPerfCommandStartIntervalUpperBoundMinutes); 116 ScheduleCollection(base::TimeDelta::FromMinutes(collection_interval_minutes)); 117} 118 119PerfProvider::~PerfProvider() {} 120 121bool PerfProvider::GetPerfData(PerfDataProto* perf_data_proto) { 122 DCHECK(CalledOnValidThread()); 123 if (state_ != READY_TO_UPLOAD) { 124 AddToPerfHistogram(NOT_READY_TO_UPLOAD); 125 return false; 126 } 127 128 *perf_data_proto = perf_data_proto_; 129 state_ = READY_TO_COLLECT; 130 131 AddToPerfHistogram(SUCCESS); 132 return true; 133} 134 135void PerfProvider::ScheduleCollection(const base::TimeDelta& interval) { 136 DCHECK(CalledOnValidThread()); 137 if (timer_.IsRunning()) 138 return; 139 140 timer_.Start(FROM_HERE, interval, this, 141 &PerfProvider::CollectIfNecessaryAndReschedule); 142} 143 144void PerfProvider::CollectIfNecessary() { 145 DCHECK(CalledOnValidThread()); 146 if (state_ != READY_TO_COLLECT) { 147 AddToPerfHistogram(NOT_READY_TO_COLLECT); 148 return; 149 } 150 151 // For privacy reasons, Chrome should only collect perf data if there is no 152 // incognito session active (or gets spawned during the collection). 153 if (BrowserList::IsOffTheRecordSessionActive()) { 154 AddToPerfHistogram(INCOGNITO_ACTIVE); 155 return; 156 } 157 158 scoped_ptr<WindowedIncognitoObserver> incognito_observer( 159 new WindowedIncognitoObserver); 160 161 chromeos::DebugDaemonClient* client = 162 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); 163 164 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds( 165 kPerfCommandDurationDefaultSeconds); 166 167 client->GetPerfData(collection_duration.InSeconds(), 168 base::Bind(&PerfProvider::ParseProtoIfValid, 169 weak_factory_.GetWeakPtr(), 170 base::Passed(&incognito_observer))); 171} 172 173void PerfProvider::CollectIfNecessaryAndReschedule() { 174 CollectIfNecessary(); 175 ScheduleCollection( 176 base::TimeDelta::FromSeconds(kPerfCommandIntervalDefaultSeconds)); 177} 178 179void PerfProvider::ParseProtoIfValid( 180 scoped_ptr<WindowedIncognitoObserver> incognito_observer, 181 const std::vector<uint8>& data) { 182 DCHECK(CalledOnValidThread()); 183 184 if (incognito_observer->incognito_launched()) { 185 AddToPerfHistogram(INCOGNITO_LAUNCHED); 186 return; 187 } 188 189 if (!perf_data_proto_.ParseFromArray(data.data(), data.size())) { 190 AddToPerfHistogram(PROTOBUF_NOT_PARSED); 191 perf_data_proto_.Clear(); 192 return; 193 } 194 195 state_ = READY_TO_UPLOAD; 196} 197} // namespace metrics 198