diff options
Diffstat (limited to 'chrome/browser/performance_monitor')
23 files changed, 34 insertions, 4281 deletions
diff --git a/chrome/browser/performance_monitor/BUILD.gn b/chrome/browser/performance_monitor/BUILD.gn deleted file mode 100644 index a763a6c..0000000 --- a/chrome/browser/performance_monitor/BUILD.gn +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//extensions/generated_extensions_api.gni") - -generated_extensions_api("performance_monitor") { - sources = [ "events.json" ] - root_namespace = "performance_monitor::%(namespace)s" - schemas = true -} diff --git a/chrome/browser/performance_monitor/constants.cc b/chrome/browser/performance_monitor/constants.cc deleted file mode 100644 index b39f0d3..0000000 --- a/chrome/browser/performance_monitor/constants.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/constants.h" - -namespace performance_monitor { - -// The error message displayed when a metric's details are not found. -const char kMetricNotFoundError[] = "Metric details not found."; - -// Any metric that is not associated with a specific activity will use this as -// its activity. -const char kProcessChromeAggregate[] = "chrome_aggregate"; - -// Tokens to retrieve state values from the database. - -// Stores information about the previous chrome version. -const char kStateChromeVersion[] = "chrome_version"; -// The prefix to the state of a profile's name, to prevent any possible naming -// collisions in the database. -const char kStateProfilePrefix[] = "profile"; - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/constants.h b/chrome/browser/performance_monitor/constants.h deleted file mode 100644 index 84dfb8e..0000000 --- a/chrome/browser/performance_monitor/constants.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_CONSTANTS_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_CONSTANTS_H_ - -#include "base/basictypes.h" -#include "base/time/time.h" - -namespace performance_monitor { - -// Constants which are used by the PerformanceMonitor and its related classes. -// The constants should be documented alongside the definition of their values -// in the .cc file. - -extern const char kMetricNotFoundError[]; -extern const char kProcessChromeAggregate[]; - -// State tokens -extern const char kStateChromeVersion[]; -extern const char kStateProfilePrefix[]; - -// The interval the watched processes are sampled for performance metrics. -const int kSampleIntervalInSeconds = 10; -// The default interval at which PerformanceMonitor performs its timed -// collections; this can be overridden by using the kPerformanceMonitorGathering -// switch with an associated (positive integer) value. -const int kDefaultGatherIntervalInSeconds = 120; - -// Unit values (for use in metric, and on the UI side). - -// Memory measurements -const int64 kBytesPerKilobyte = 1 << 10; -const int64 kBytesPerMegabyte = kBytesPerKilobyte * (1 << 10); -const int64 kBytesPerGigabyte = kBytesPerMegabyte * (1 << 10); -const int64 kBytesPerTerabyte = kBytesPerGigabyte * (1 << 10); - -// Time measurements - Most of these are imported from base/time/time.h -// These units are used for display (and it's related calculations), not for -// any mathematical analysis. Thus we can estimate for values without an exact -// conversion. -const int64 kMicrosecondsPerMonth = base::Time::kMicrosecondsPerDay * 30; -const int64 kMicrosecondsPerYear = base::Time::kMicrosecondsPerDay * 365; - -// Performance alert thresholds - -// If a process is consistently above this CPU utilization percentage over time, -// we consider it as high and may take action. -const float kHighCPUUtilizationThreshold = 90.0f; -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_CONSTANTS_H_ diff --git a/chrome/browser/performance_monitor/database.cc b/chrome/browser/performance_monitor/database.cc deleted file mode 100644 index f3522d2..0000000 --- a/chrome/browser/performance_monitor/database.cc +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/database.h" - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "chrome/browser/performance_monitor/key_builder.h" -#include "chrome/common/chrome_paths.h" -#include "content/public/browser/browser_thread.h" -#include "third_party/leveldatabase/src/include/leveldb/db.h" -#include "third_party/leveldatabase/src/include/leveldb/iterator.h" -#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" - -namespace performance_monitor { -namespace { -const char kDbDir[] = "Performance Monitor Databases"; -const char kRecentDb[] = "Recent Metrics"; -const char kMaxValueDb[] = "Max Value Metrics"; -const char kEventDb[] = "Events"; -const char kStateDb[] = "Configuration"; -const char kActiveIntervalDb[] = "Active Interval"; -const char kMetricDb[] = "Metrics"; -const double kDefaultMaxValue = 0.0; - -// If the db is quiet for this number of minutes, then it is considered down. -const base::TimeDelta kActiveIntervalTimeout() { - return base::TimeDelta::FromMinutes(5); -} - -TimeRange ActiveIntervalToTimeRange(const std::string& start_time, - const std::string& end_time) { - int64 start_time_int = 0; - int64 end_time_int = 0; - base::StringToInt64(start_time, &start_time_int); - base::StringToInt64(end_time, &end_time_int); - return TimeRange(base::Time::FromInternalValue(start_time_int), - base::Time::FromInternalValue(end_time_int)); -} - -double StringToDouble(const std::string& s) { - double value = 0.0; - if (!base::StringToDouble(s, &value)) - LOG(ERROR) << "Failed to convert " << s << " to double."; - return value; -} - -// Returns an event from the given JSON string; the scoped_ptr will be NULL if -// we are unable to properly parse the JSON. -scoped_ptr<Event> EventFromJSON(const std::string& data) { - base::Value* value = base::JSONReader::Read(data); - base::DictionaryValue* dict = NULL; - if (!value || !value->GetAsDictionary(&dict)) - return scoped_ptr<Event>(); - - return Event::FromValue(scoped_ptr<base::DictionaryValue>(dict)); -} - -} // namespace - -const char Database::kDatabaseSequenceToken[] = - "_performance_monitor_db_sequence_token_"; - -TimeRange::TimeRange() { -} - -TimeRange::TimeRange(base::Time start_time, base::Time end_time) - : start(start_time), - end(end_time) { -} - -TimeRange::~TimeRange() { -} - -base::Time Database::SystemClock::GetTime() { - return base::Time::Now(); -} - -// Static -scoped_ptr<Database> Database::Create(base::FilePath path) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - if (path.empty()) { - CHECK(PathService::Get(chrome::DIR_USER_DATA, &path)); - path = path.AppendASCII(kDbDir); - } - scoped_ptr<Database> database; - if (!base::DirectoryExists(path) && !base::CreateDirectory(path)) - return database.Pass(); - database.reset(new Database(path)); - - // If the database did not initialize correctly, return a NULL scoped_ptr. - if (!database->valid_) - database.reset(); - return database.Pass(); -} - -bool Database::AddStateValue(const std::string& key, const std::string& value) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - UpdateActiveInterval(); - leveldb::Status insert_status = state_db_->Put(write_options_, key, value); - return insert_status.ok(); -} - -std::string Database::GetStateValue(const std::string& key) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::string result; - state_db_->Get(read_options_, key, &result); - return result; -} - -bool Database::AddEvent(const Event& event) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - UpdateActiveInterval(); - std::string value; - base::JSONWriter::Write(event.data(), &value); - std::string key = key_builder_->CreateEventKey(event.time(), event.type()); - leveldb::Status status = event_db_->Put(write_options_, key, value); - return status.ok(); -} - -std::vector<TimeRange> Database::GetActiveIntervals(const base::Time& start, - const base::Time& end) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::vector<TimeRange> results; - std::string start_key = key_builder_->CreateActiveIntervalKey(start); - std::string end_key = key_builder_->CreateActiveIntervalKey(end); - scoped_ptr<leveldb::Iterator> it(active_interval_db_->NewIterator( - read_options_)); - it->Seek(start_key); - // If the interator is valid, we check the previous value in case we jumped - // into the middle of an active interval. If the iterator is not valid, then - // the key may be in the current active interval. - if (it->Valid()) - it->Prev(); - else - it->SeekToLast(); - if (it->Valid() && it->value().ToString() > start_key) { - results.push_back(ActiveIntervalToTimeRange(it->key().ToString(), - it->value().ToString())); - } - - for (it->Seek(start_key); - it->Valid() && it->key().ToString() < end_key; - it->Next()) { - results.push_back(ActiveIntervalToTimeRange(it->key().ToString(), - it->value().ToString())); - } - return results; -} - -Database::EventVector Database::GetEvents(EventType type, - const base::Time& start, - const base::Time& end) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - EventVector events; - std::string start_key = - key_builder_->CreateEventKey(start, EVENT_UNDEFINED); - std::string end_key = - key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); - leveldb::WriteBatch invalid_entries; - scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); - for (it->Seek(start_key); - it->Valid() && it->key().ToString() <= end_key; - it->Next()) { - if (type != EVENT_UNDEFINED) { - EventType key_type = - key_builder_->EventKeyToEventType(it->key().ToString()); - if (key_type != type) - continue; - } - scoped_ptr<Event> event = EventFromJSON(it->value().ToString()); - if (!event.get()) { - invalid_entries.Delete(it->key()); - LOG(ERROR) << "Found invalid event in the database. JSON: '" - << it->value().ToString() - << "'. Erasing event from the database."; - continue; - } - events.push_back(linked_ptr<Event>(event.release())); - } - event_db_->Write(write_options_, &invalid_entries); - return events; -} - -Database::EventTypeSet Database::GetEventTypes(const base::Time& start, - const base::Time& end) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - EventTypeSet results; - std::string start_key = - key_builder_->CreateEventKey(start, EVENT_UNDEFINED); - std::string end_key = - key_builder_->CreateEventKey(end, EVENT_NUMBER_OF_EVENTS); - scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_)); - for (it->Seek(start_key); - it->Valid() && it->key().ToString() <= end_key; - it->Next()) { - EventType key_type = - key_builder_->EventKeyToEventType(it->key().ToString()); - results.insert(key_type); - } - return results; -} - -bool Database::AddMetric(const std::string& activity, - const Metric& metric) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - if (!metric.IsValid()) { - DLOG(ERROR) << "Metric to be added is invalid. Type: " << metric.type - << ", Time: " << metric.time.ToInternalValue() - << ", Value: " << metric.value << ". Ignoring."; - return false; - } - - UpdateActiveInterval(); - std::string recent_key = - key_builder_->CreateRecentKey(metric.time, metric.type, activity); - std::string metric_key = - key_builder_->CreateMetricKey(metric.time, metric.type, activity); - std::string recent_map_key = - key_builder_->CreateRecentMapKey(metric.type, activity); - // Use recent_map_ to quickly find the key that must be removed. - RecentMap::iterator old_it = recent_map_.find(recent_map_key); - if (old_it != recent_map_.end()) - recent_db_->Delete(write_options_, old_it->second); - recent_map_[recent_map_key] = recent_key; - leveldb::Status recent_status = - recent_db_->Put(write_options_, recent_key, metric.ValueAsString()); - leveldb::Status metric_status = - metric_db_->Put(write_options_, metric_key, metric.ValueAsString()); - - bool max_value_success = - UpdateMaxValue(activity, metric.type, metric.ValueAsString()); - return recent_status.ok() && metric_status.ok() && max_value_success; -} - -bool Database::UpdateMaxValue(const std::string& activity, - MetricType metric, - const std::string& value) { - std::string max_value_key( - key_builder_->CreateMaxValueKey(metric, activity)); - bool has_key = ContainsKey(max_value_map_, max_value_key); - if ((has_key && StringToDouble(value) > max_value_map_[max_value_key]) || - !has_key) { - max_value_map_[max_value_key] = StringToDouble(value); - return max_value_db_->Put(write_options_, max_value_key, value).ok(); - } - - return true; -} - -Database::MetricTypeSet Database::GetActiveMetrics(const base::Time& start, - const base::Time& end) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::string recent_start_key = key_builder_->CreateRecentKey( - start, static_cast<MetricType>(0), std::string()); - std::string recent_end_key = key_builder_->CreateRecentKey( - end, METRIC_NUMBER_OF_METRICS, std::string()); - std::string recent_end_of_time_key = key_builder_->CreateRecentKey( - clock_->GetTime(), METRIC_NUMBER_OF_METRICS, std::string()); - - MetricTypeSet active_metrics; - // Get all the guaranteed metrics. - scoped_ptr<leveldb::Iterator> recent_it( - recent_db_->NewIterator(read_options_)); - for (recent_it->Seek(recent_start_key); - recent_it->Valid() && recent_it->key().ToString() <= recent_end_key; - recent_it->Next()) { - RecentKey split_key = - key_builder_->SplitRecentKey(recent_it->key().ToString()); - active_metrics.insert(split_key.type); - } - // Get all the possible metrics (metrics that may have been updated after - // |end|). - MetricTypeSet possible_metrics; - for (recent_it->Seek(recent_end_key); - recent_it->Valid() && - recent_it->key().ToString() <= recent_end_of_time_key; - recent_it->Next()) { - RecentKey split_key = - key_builder_->SplitRecentKey(recent_it->key().ToString()); - possible_metrics.insert(split_key.type); - } - MetricTypeSet::iterator possible_it; - scoped_ptr<leveldb::Iterator> metric_it( - metric_db_->NewIterator(read_options_)); - for (possible_it = possible_metrics.begin(); - possible_it != possible_metrics.end(); - ++possible_it) { - std::string metric_start_key = - key_builder_->CreateMetricKey(start, *possible_it,std::string()); - std::string metric_end_key = - key_builder_->CreateMetricKey(end, *possible_it, std::string()); - metric_it->Seek(metric_start_key); - // Stats in the timerange from any activity makes the metric active. - if (metric_it->Valid() && metric_it->key().ToString() <= metric_end_key) { - active_metrics.insert(*possible_it); - } - } - - return active_metrics; -} - -std::set<std::string> Database::GetActiveActivities(MetricType metric_type, - const base::Time& start) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::set<std::string> results; - std::string start_key = key_builder_->CreateRecentKey( - start, static_cast<MetricType>(0), std::string()); - scoped_ptr<leveldb::Iterator> it(recent_db_->NewIterator(read_options_)); - for (it->Seek(start_key); it->Valid(); it->Next()) { - RecentKey split_key = - key_builder_->SplitRecentKey(it->key().ToString()); - if (split_key.type == metric_type) - results.insert(split_key.activity); - } - return results; -} - -double Database::GetMaxStatsForActivityAndMetric(const std::string& activity, - MetricType metric) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::string max_value_key( - key_builder_->CreateMaxValueKey(metric, activity)); - if (ContainsKey(max_value_map_, max_value_key)) - return max_value_map_[max_value_key]; - return kDefaultMaxValue; -} - -bool Database::GetRecentStatsForActivityAndMetric(const std::string& activity, - MetricType metric_type, - Metric* metric) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::string recent_map_key = - key_builder_->CreateRecentMapKey(metric_type, activity); - if (!ContainsKey(recent_map_, recent_map_key)) - return false; - std::string recent_key = recent_map_[recent_map_key]; - - std::string result; - leveldb::Status status = recent_db_->Get(read_options_, recent_key, &result); - if (status.ok()) - *metric = Metric(metric_type, - key_builder_->SplitRecentKey(recent_key).time, - result); - return status.ok(); -} - -scoped_ptr<Database::MetricVector> Database::GetStatsForActivityAndMetric( - const std::string& activity, - MetricType metric_type, - const base::Time& start, - const base::Time& end) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - scoped_ptr<MetricVector> results(new MetricVector()); - std::string start_key = - key_builder_->CreateMetricKey(start, metric_type, activity); - std::string end_key = - key_builder_->CreateMetricKey(end, metric_type, activity); - leveldb::WriteBatch invalid_entries; - scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); - for (it->Seek(start_key); - it->Valid() && it->key().ToString() <= end_key; - it->Next()) { - MetricKey split_key = - key_builder_->SplitMetricKey(it->key().ToString()); - if (split_key.activity == activity) { - Metric metric(metric_type, split_key.time, it->value().ToString()); - if (!metric.IsValid()) { - invalid_entries.Delete(it->key()); - LOG(ERROR) << "Found bad metric in the database. Type: " - << metric.type << ", Time: " << metric.time.ToInternalValue() - << ", Value: " << metric.value - << ". Erasing metric from database."; - continue; - } - results->push_back(metric); - } - } - metric_db_->Write(write_options_, &invalid_entries); - return results.Pass(); -} - -Database::MetricVectorMap Database::GetStatsForMetricByActivity( - MetricType metric_type, - const base::Time& start, - const base::Time& end) { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - MetricVectorMap results; - std::string start_key = - key_builder_->CreateMetricKey(start, metric_type, std::string()); - std::string end_key = - key_builder_->CreateMetricKey(end, metric_type, std::string()); - leveldb::WriteBatch invalid_entries; - scoped_ptr<leveldb::Iterator> it(metric_db_->NewIterator(read_options_)); - for (it->Seek(start_key); - it->Valid() && it->key().ToString() <= end_key; - it->Next()) { - MetricKey split_key = key_builder_->SplitMetricKey(it->key().ToString()); - if (!results[split_key.activity].get()) { - results[split_key.activity] = - linked_ptr<MetricVector >(new MetricVector()); - } - Metric metric(metric_type, split_key.time, it->value().ToString()); - if (!metric.IsValid()) { - invalid_entries.Delete(it->key()); - LOG(ERROR) << "Found bad metric in the database. Type: " - << metric.type << ", Time: " << metric.time.ToInternalValue() - << ", Value: " << metric.value - << ". Erasing metric from database."; - continue; - } - results[split_key.activity]->push_back(metric); - } - metric_db_->Write(write_options_, &invalid_entries); - return results; -} - -Database::Database(const base::FilePath& path) - : key_builder_(new KeyBuilder()), - path_(path), - read_options_(leveldb::ReadOptions()), - write_options_(leveldb::WriteOptions()), - valid_(false) { - if (!InitDBs()) - return; - LoadRecents(); - LoadMaxValues(); - clock_ = scoped_ptr<Clock>(new SystemClock()); - valid_ = true; -} - -Database::~Database() { -} - -bool Database::InitDBs() { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - leveldb::Options open_options; - open_options.max_open_files = 0; // Use minimum. - open_options.create_if_missing = true; - - // TODO (rdevlin.cronin): This code is ugly. Fix it. - recent_db_ = SafelyOpenDatabase(open_options, - kRecentDb, - true); // fix if damaged - max_value_db_ = SafelyOpenDatabase(open_options, - kMaxValueDb, - true); // fix if damaged - state_db_ = SafelyOpenDatabase(open_options, - kStateDb, - true); // fix if damaged - active_interval_db_ = SafelyOpenDatabase(open_options, - kActiveIntervalDb, - true); // fix if damaged - metric_db_ = SafelyOpenDatabase(open_options, - kMetricDb, - true); // fix if damaged - event_db_ = SafelyOpenDatabase(open_options, - kEventDb, - true); // fix if damaged - return recent_db_ && max_value_db_ && state_db_ && - active_interval_db_ && metric_db_ && event_db_; -} - -scoped_ptr<leveldb::DB> Database::SafelyOpenDatabase( - const leveldb::Options& options, - const std::string& path, - bool fix_if_damaged) { -#if defined(OS_POSIX) - std::string name = path_.AppendASCII(path).value(); -#elif defined(OS_WIN) - std::string name = base::WideToUTF8(path_.AppendASCII(path).value()); -#endif - - leveldb::DB* database; - leveldb::Status status = leveldb::DB::Open(options, name, &database); - // If all goes well, return the database. - if (status.ok()) - return scoped_ptr<leveldb::DB>(database); - - // Return NULL and print the error if we either didn't find the database and - // don't want to create it, or if we don't want to try to fix it. - if ((status.IsNotFound() && !options.create_if_missing) || !fix_if_damaged) { - LOG(ERROR) << status.ToString(); - return scoped_ptr<leveldb::DB>(); - } - // Otherwise, we have an error (corruption, io error, or a not found error - // even if we tried to create it). - // - // First, we try again. - LOG(ERROR) << "Database error: " << status.ToString() << ". Trying again."; - status = leveldb::DB::Open(options, name, &database); - // If we fail on corruption, we can try to repair it. - if (status.IsCorruption()) { - LOG(ERROR) << "Database corrupt (second attempt). Trying to repair."; - status = leveldb::RepairDB(name, options); - // If the repair succeeds and we can open the database, return the - // database. Otherwise, continue on. - if (status.ok()) { - status = leveldb::DB::Open(options, name, &database); - if (status.ok()) - return scoped_ptr<leveldb::DB>(database); - } - LOG(ERROR) << "Repair failed. Deleting database."; - } - // Next, try to delete and recreate the database. Return NULL if we fail - // on either of these steps. - status = leveldb::DestroyDB(name, options); - if (!status.ok()) { - LOG(ERROR) << "Failed to delete database. " << status.ToString(); - return scoped_ptr<leveldb::DB>(); - } - // If we don't have the create_if_missing option, add it (it's safe to - // assume this is okay, since we have permission to |fix_if_damaged|). - if (!options.create_if_missing) { - leveldb::Options create_options(options); - create_options.create_if_missing = true; - status = leveldb::DB::Open(create_options, name, &database); - } else { - status = leveldb::DB::Open(options, name, &database); - } - // There's nothing else we can try at this point. - if (status.ok()) - return scoped_ptr<leveldb::DB>(database); - // Return the database if we succeeded, or NULL on failure. - LOG(ERROR) << "Failed to recreate database. " << status.ToString(); - return scoped_ptr<leveldb::DB>(); -} - -bool Database::Close() { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - metric_db_.reset(); - event_db_.reset(); - recent_db_.reset(); - max_value_db_.reset(); - state_db_.reset(); - active_interval_db_.reset(); - start_time_key_.clear(); - return true; -} - -void Database::LoadRecents() { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - recent_map_.clear(); - scoped_ptr<leveldb::Iterator> it(recent_db_->NewIterator(read_options_)); - for (it->SeekToFirst(); it->Valid(); it->Next()) { - RecentKey split_key = key_builder_->SplitRecentKey(it->key().ToString()); - recent_map_[key_builder_-> - CreateRecentMapKey(split_key.type, split_key.activity)] = - it->key().ToString(); - } -} - -void Database::LoadMaxValues() { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - max_value_map_.clear(); - scoped_ptr<leveldb::Iterator> it(max_value_db_->NewIterator(read_options_)); - for (it->SeekToFirst(); it->Valid(); it->Next()) { - max_value_map_[it->key().ToString()] = - StringToDouble(it->value().ToString()); - } -} - -// TODO(chebert): Only update the active interval under certian circumstances -// eg. every 10 times or when forced. -void Database::UpdateActiveInterval() { - CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - base::Time current_time = clock_->GetTime(); - std::string end_time; - // If the last update was too long ago. - if (start_time_key_.empty() || - current_time - last_update_time_ > kActiveIntervalTimeout()) { - start_time_key_ = key_builder_->CreateActiveIntervalKey(current_time); - end_time = start_time_key_; - } else { - end_time = key_builder_->CreateActiveIntervalKey(clock_->GetTime()); - } - last_update_time_ = current_time; - active_interval_db_->Put(write_options_, start_time_key_, end_time); -} - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/database.h b/chrome/browser/performance_monitor/database.h deleted file mode 100644 index 87082cd..0000000 --- a/chrome/browser/performance_monitor/database.h +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_DATABASE_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_DATABASE_H_ - -#include <set> -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "base/gtest_prod_util.h" -#include "base/memory/linked_ptr.h" -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" -#include "chrome/browser/performance_monitor/constants.h" -#include "chrome/browser/performance_monitor/event.h" -#include "chrome/browser/performance_monitor/metric.h" -#include "third_party/leveldatabase/src/include/leveldb/db.h" - -namespace performance_monitor { - -struct TimeRange { - TimeRange(); - TimeRange(base::Time start_time, base::Time end_time); - ~TimeRange(); - - base::Time start; - base::Time end; -}; - -class KeyBuilder; -class DatabaseTestHelper; - -// The class supporting all performance monitor storage. This class wraps -// multiple leveldb::DB objects. All methods must be called from a background -// thread. Callers should use BrowserThread::PostBlockingPoolSequencedTask using -// performance_monitor::kDBSequenceToken as the sequence token. -// -// Different schemas are used for the different leveldb::DB's based off of the -// structure of the data and the common ways that it will need to be accessed. -// The following specifies the schema of each type of leveldb::DB. Delimiters -// are denoted with a '-'. -// -// State DB: -// Stores information about the configuration or 'state' of the browser. Things -// like browser version go in here. -// Key: Unique Identifier -// Value: State Value -// -// Active Interval DB: -// Stores information about when there is data in the database. When the -// database is constructed, the time is noted as the start of the active -// interval. Then, every write operation the current time is marked as the end -// of the current active interval. If the database has no write operations for -// a certain amount of time, then the database is considered inactive for that -// time period and a new start time is noted. Having the key be the beginning -// of the active interval allows for efficient upserts to the current active -// interval. If the end of the active interval was in the key, then every update -// to the active interval would have to remove a key and insert a new one. -// Key: Beginning of ActiveInterval -// Value: End of ActiveInterval -// -// Event DB: -// Stores all events. A time and type is enough to uniquely identify an event. -// Using the time that the event took place as the beginning of the key allows -// us to efficiently answer the question: "What are all the events that took -// place in this time range?". -// Key: Time - Type -// Value: Event in JSON -// -// Recent DB: -// Stores the most recent metric statistics to go into the database. There is -// only ever one entry per (metric, activity) pair. |recent_map_| keeps an -// in-memory version of this database with a mapping from a concatenation of -// metric and activity to the key used in the recent db. |recent_map_| allows us -// to quickly find the key that must be replaced in the recent db. This -// database becomes useful when it is necessary to find all the active metrics -// within a timerange. Without it, all the metric databases would need to be -// searched to see if that metric is active. -// Key: Time - Metric - Activity -// Value: Statistic -// -// Max Value DB: -// Stores the max metric statistics that have been inserted into the database. -// There is only ever one entry per (metric, activity) pair. |max_value_map_| -// keeps an in-memory version of this database with a mapping from a -// concatenation of metric and activity to the max metric. -// Key: Metric - Activity -// Value: Statistic -// -// Metric DB: -// Stores the statistics for different metrics. Having the time before the -// activity ensures that the search space can only be as large as the time -// interval. -// Key: Metric - Time - Activity -// Value: Statistic -class Database { - public: - typedef std::set<EventType> EventTypeSet; - typedef std::vector<linked_ptr<Event> > EventVector; - typedef std::set<MetricType> MetricTypeSet; - typedef std::vector<Metric> MetricVector; - typedef std::map<std::string, linked_ptr<MetricVector> > MetricVectorMap; - - static const char kDatabaseSequenceToken[]; - - // The class that the database will use to infer time. Abstracting out the - // time mechanism allows for easy testing and mock data insetion. - class Clock { - public: - Clock() {} - virtual ~Clock() {} - virtual base::Time GetTime() = 0; - }; - - virtual ~Database(); - - static scoped_ptr<Database> Create(base::FilePath path); - - // A "state" value is anything that can only have one value at a time, and - // usually describes the state of the browser eg. version. - bool AddStateValue(const std::string& key, const std::string& value); - - std::string GetStateValue(const std::string& key); - - // Add an event to the database. - bool AddEvent(const Event& event); - - // Retrieve the events from the database. These methods populate the provided - // vector, and will search on the given criteria. - EventVector GetEvents(EventType type, - const base::Time& start, - const base::Time& end); - - EventVector GetEvents(const base::Time& start, const base::Time& end) { - return GetEvents(EVENT_UNDEFINED, start, end); - } - - EventVector GetEvents(EventType type) { - return GetEvents(type, base::Time(), clock_->GetTime()); - } - - EventVector GetEvents() { - return GetEvents(EVENT_UNDEFINED, base::Time(), clock_->GetTime()); - } - - EventTypeSet GetEventTypes(const base::Time& start, const base::Time& end); - - EventTypeSet GetEventTypes() { - return GetEventTypes(base::Time(), clock_->GetTime()); - } - - // Add a metric instance to the database. - bool AddMetric(const std::string& activity, const Metric& metric); - - bool AddMetric(const Metric& metric) { - return AddMetric(kProcessChromeAggregate, metric); - } - - // Get the metrics that are active for the given process between |start| - // (inclusive) and |end| (exclusive). - MetricTypeSet GetActiveMetrics(const base::Time& start, - const base::Time& end); - - // Get the activities that are active for the given metric after |start|. - std::set<std::string> GetActiveActivities(MetricType metric_type, - const base::Time& start); - - // Get the max value for the given metric in the db. - double GetMaxStatsForActivityAndMetric(const std::string& activity, - MetricType metric_type); - double GetMaxStatsForActivityAndMetric(MetricType metric_type) { - return GetMaxStatsForActivityAndMetric(kProcessChromeAggregate, - metric_type); - } - - // Populate info with the most recent activity. Return false if populate - // was unsuccessful. - bool GetRecentStatsForActivityAndMetric(const std::string& activity, - MetricType metric_type, - Metric* metric); - - bool GetRecentStatsForActivityAndMetric(MetricType metric_type, - Metric* metric) { - return GetRecentStatsForActivityAndMetric(kProcessChromeAggregate, - metric_type, - metric); - } - - // Query given |metric_type| and |activity|. - scoped_ptr<MetricVector> GetStatsForActivityAndMetric( - const std::string& activity, - MetricType metric_type, - const base::Time& start, - const base::Time& end); - - scoped_ptr<MetricVector> GetStatsForActivityAndMetric( - MetricType metric_type, const base::Time& start, const base::Time& end) { - return GetStatsForActivityAndMetric(kProcessChromeAggregate, metric_type, - start, end); - } - - scoped_ptr<MetricVector> GetStatsForActivityAndMetric( - const std::string& activity, MetricType metric_type) { - return GetStatsForActivityAndMetric(activity, metric_type, base::Time(), - clock_->GetTime()); - } - - scoped_ptr<MetricVector> GetStatsForActivityAndMetric( - MetricType metric_type) { - return GetStatsForActivityAndMetric(kProcessChromeAggregate, metric_type, - base::Time(), clock_->GetTime()); - } - - // Query given |metric_type|. The returned map is keyed by activity. - MetricVectorMap GetStatsForMetricByActivity(MetricType metric_type, - const base::Time& start, - const base::Time& end); - - MetricVectorMap GetStatsForMetricByActivity(MetricType metric_type) { - return GetStatsForMetricByActivity( - metric_type, base::Time(), clock_->GetTime()); - } - - // Returns the active time intervals that overlap with the time interval - // defined by |start| and |end|. - std::vector<TimeRange> GetActiveIntervals(const base::Time& start, - const base::Time& end); - - base::FilePath path() const { return path_; } - - void set_clock(scoped_ptr<Clock> clock) { - clock_ = clock.Pass(); - } - - private: - friend class DatabaseTestHelper; - - typedef std::map<std::string, std::string> RecentMap; - typedef std::map<std::string, double> MaxValueMap; - - // By default, the database uses a clock that simply returns the current time. - class SystemClock : public Clock { - public: - SystemClock() {} - virtual ~SystemClock() {} - virtual base::Time GetTime() OVERRIDE; - }; - - explicit Database(const base::FilePath& path); - - bool InitDBs(); - - // Attempts to open a database, and tries to fix it if it is corrupt or - // damaged (if |fix_if_damaged| is true). Returns a scoped_ptr to the - // database on success, or NULL on failure. - scoped_ptr<leveldb::DB> SafelyOpenDatabase( - const leveldb::Options& options, - const std::string& path, - bool fix_if_damaged); - - bool Close(); - - // Load recent info from the db into recent_map_. - void LoadRecents(); - // Load max values from the db into the max_value_map_. - void LoadMaxValues(); - - // Mark the database as being active for the current time. - void UpdateActiveInterval(); - // Updates the max_value_map_ and max_value_db_ if the value is greater than - // the current max value for the given activity and metric. - bool UpdateMaxValue(const std::string& activity, - MetricType metric, - const std::string& value); - - scoped_ptr<KeyBuilder> key_builder_; - - // A mapping of id,metric to the last inserted key for those parameters - // is maintained to prevent having to search through the recent db every - // insert. - RecentMap recent_map_; - - MaxValueMap max_value_map_; - - // The directory where all the databases will reside. - base::FilePath path_; - - // The key for the beginning of the active interval. - std::string start_time_key_; - - // The last time the database had a transaction. - base::Time last_update_time_; - - scoped_ptr<Clock> clock_; - - scoped_ptr<leveldb::DB> recent_db_; - - scoped_ptr<leveldb::DB> max_value_db_; - - scoped_ptr<leveldb::DB> state_db_; - - scoped_ptr<leveldb::DB> active_interval_db_; - - scoped_ptr<leveldb::DB> metric_db_; - - scoped_ptr<leveldb::DB> event_db_; - - leveldb::ReadOptions read_options_; - leveldb::WriteOptions write_options_; - - // Indicates whether or not the database successfully initialized. If false, - // the Create() call will return NULL. - bool valid_; - - DISALLOW_COPY_AND_ASSIGN(Database); -}; - -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_DATABASE_H_ diff --git a/chrome/browser/performance_monitor/database_unittest.cc b/chrome/browser/performance_monitor/database_unittest.cc deleted file mode 100644 index dd4b012..0000000 --- a/chrome/browser/performance_monitor/database_unittest.cc +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <algorithm> -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" -#include "chrome/browser/performance_monitor/database.h" -#include "chrome/browser/performance_monitor/key_builder.h" -#include "chrome/browser/performance_monitor/metric.h" -#include "chrome/browser/performance_monitor/performance_monitor_util.h" -#include "extensions/common/extension.h" -#include "extensions/common/manifest.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/leveldatabase/src/include/leveldb/db.h" -#include "third_party/leveldatabase/src/include/leveldb/iterator.h" - -using extensions::Extension; -using extensions::Manifest; - -namespace performance_monitor { - -// A class which is friended by Database, in order to hold the private methods -// and avoid friending all the different test classes. -class DatabaseTestHelper { - public: - explicit DatabaseTestHelper(Database* database) : database_(database) { } - ~DatabaseTestHelper() { } - - bool Close() { return database_->Close(); } - - // Override the check for a metric's validity and insert it in the database. - // Note: This does not do extraneous updates, like updating the recent_db or - // the max_value_map. - bool AddInvalidMetric(std::string activity, Metric metric) { - std::string metric_key = - database_->key_builder_->CreateMetricKey(database_->clock_->GetTime(), - metric.type, - activity); - leveldb::Status status = - database_->metric_db_->Put(database_->write_options_, - metric_key, - metric.ValueAsString()); - return status.ok(); - } - - // Writes an invalid event to the database; since events are stored as JSON - // strings, this is equivalent to writing a garbage string. - bool AddInvalidEvent(base::Time time, EventType type) { - std::string key = database_->key_builder_->CreateEventKey(time, type); - leveldb::Status status = - database_->event_db_->Put(database_->write_options_, key, "fake_event"); - return status.ok(); - } - - size_t GetNumberOfMetricEntries() { - return GetNumberOfEntries(database_->metric_db_.get()); - } - size_t GetNumberOfEventEntries() { - return GetNumberOfEntries(database_->event_db_.get()); - } - - private: - // Returns the number of entries in a given database. - size_t GetNumberOfEntries(leveldb::DB* level_db) { - size_t number_of_entries = 0; - scoped_ptr<leveldb::Iterator> iter( - level_db->NewIterator(database_->read_options_)); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) - ++number_of_entries; - return number_of_entries; - } - - Database* database_; -}; - -// A clock that increments every access. Great for testing. -class TestingClock : public Database::Clock { - public: - TestingClock() - : counter_(0) { - } - explicit TestingClock(const TestingClock& other) - : counter_(other.counter_) { - } - virtual ~TestingClock() {} - virtual base::Time GetTime() OVERRIDE { - return base::Time::FromInternalValue(++counter_); - } - private: - int64 counter_; -}; - -class PerformanceMonitorDatabaseEventTest : public ::testing::Test { - protected: - PerformanceMonitorDatabaseEventTest() { - clock_ = new TestingClock(); - CHECK(temp_dir_.CreateUniqueTempDir()); - db_ = Database::Create(temp_dir_.path()); - CHECK(db_.get()); - db_->set_clock(scoped_ptr<Database::Clock>(clock_)); - } - - virtual void SetUp() { - ASSERT_TRUE(db_.get()); - PopulateDB(); - } - - void PopulateDB() { - InitEvents(); - db_->AddEvent(*install_event_1_.get()); - db_->AddEvent(*install_event_2_.get()); - db_->AddEvent(*uninstall_event_1_.get()); - db_->AddEvent(*uninstall_event_2_.get()); - } - - scoped_ptr<Database> db_; - Database::Clock* clock_; - base::ScopedTempDir temp_dir_; - scoped_ptr<Event> install_event_1_; - scoped_ptr<Event> install_event_2_; - scoped_ptr<Event> uninstall_event_1_; - scoped_ptr<Event> uninstall_event_2_; - - private: - void InitEvents() { - install_event_1_ = util::CreateExtensionEvent( - EVENT_EXTENSION_INSTALL, clock_->GetTime(), "a", "extension 1", - "http://foo.com", static_cast<int>(Manifest::UNPACKED), "0.1", - "Test Test"); - install_event_2_ = util::CreateExtensionEvent( - EVENT_EXTENSION_INSTALL, clock_->GetTime(), "b", "extension 2", - "http://bar.com", static_cast<int>(Manifest::UNPACKED), "0.1", - "Test Test"); - uninstall_event_1_ = util::CreateExtensionEvent( - EVENT_EXTENSION_UNINSTALL, clock_->GetTime(), "a", "extension 1", - "http://foo.com", static_cast<int>(Manifest::UNPACKED), "0.1", - "Test Test"); - uninstall_event_2_ = util::CreateExtensionEvent( - EVENT_EXTENSION_UNINSTALL, clock_->GetTime(), "b", "extension 2", - "http://bar.com", static_cast<int>(Manifest::UNPACKED), "0.1", - "Test Test"); - } -}; - -class PerformanceMonitorDatabaseMetricTest : public ::testing::Test { - protected: - PerformanceMonitorDatabaseMetricTest() { - clock_ = new TestingClock(); - CHECK(temp_dir_.CreateUniqueTempDir()); - db_ = Database::Create(temp_dir_.path()); - CHECK(db_.get()); - db_->set_clock(scoped_ptr<Database::Clock>(clock_)); - activity_ = std::string("A"); - } - - virtual void SetUp() { - ASSERT_TRUE(db_.get()); - PopulateDB(); - } - - void PopulateDB() { - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 50.5)); - db_->AddMetric(activity_, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 13.1)); - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_PRIVATE_MEMORY_USAGE, - clock_->GetTime(), - 1000000.0)); - db_->AddMetric(activity_, - Metric(METRIC_PRIVATE_MEMORY_USAGE, - clock_->GetTime(), - 3000000.0)); - } - - scoped_ptr<Database> db_; - Database::Clock* clock_; - base::ScopedTempDir temp_dir_; - std::string activity_; -}; - -////// PerformanceMonitorDatabaseSetupTests //////////////////////////////////// -TEST(PerformanceMonitorDatabaseSetupTest, OpenClose) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - scoped_ptr<Database> db = Database::Create(temp_dir.path()); - ASSERT_TRUE(db.get()); - DatabaseTestHelper helper(db.get()); - ASSERT_TRUE(helper.Close()); -} - -TEST(PerformanceMonitorDatabaseSetupTest, ActiveInterval) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - TestingClock* clock_1 = new TestingClock(); - base::Time start_time = clock_1->GetTime(); - - scoped_ptr<Database> db_1 = Database::Create(temp_dir.path()); - db_1->set_clock(scoped_ptr<Database::Clock>(clock_1)); - DatabaseTestHelper helper1(db_1.get()); - db_1->AddStateValue("test", "test"); - ASSERT_TRUE(db_1.get()); - ASSERT_TRUE(helper1.Close()); - - TestingClock* clock_2 = new TestingClock(*clock_1); - base::Time mid_time = clock_2->GetTime(); - scoped_ptr<Database> db_2 = Database::Create(temp_dir.path()); - db_2->set_clock(scoped_ptr<Database::Clock>(clock_2)); - DatabaseTestHelper helper2(db_2.get()); - db_2->AddStateValue("test", "test"); - ASSERT_TRUE(db_2.get()); - ASSERT_TRUE(helper2.Close()); - - TestingClock* clock_3 = new TestingClock(*clock_2); - base::Time end_time = clock_3->GetTime(); - scoped_ptr<Database> db_3 = Database::Create(temp_dir.path()); - db_3->set_clock(scoped_ptr<Database::Clock>(clock_3)); - db_3->AddStateValue("test", "test"); - ASSERT_TRUE(db_3.get()); - - std::vector<TimeRange> active_interval = db_3->GetActiveIntervals(start_time, - end_time); - ASSERT_EQ(active_interval.size(), 2u); - ASSERT_TRUE(active_interval[0].start > start_time && - active_interval[0].end < mid_time); - ASSERT_TRUE(active_interval[1].start > mid_time && - active_interval[1].end < end_time); -} - -TEST(PerformanceMonitorDatabaseSetupTest, - ActiveIntervalRetrievalDuringActiveInterval) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - TestingClock* clock = new TestingClock(); - scoped_ptr<Database> db = Database::Create(temp_dir.path()); - db->set_clock(scoped_ptr<Database::Clock>(clock)); - db->AddStateValue("test", "test"); - base::Time start_time = clock->GetTime(); - db->AddStateValue("test", "test"); - base::Time end_time = clock->GetTime(); - db->AddStateValue("test", "test"); - - std::vector<TimeRange> active_interval = db->GetActiveIntervals(start_time, - end_time); - ASSERT_EQ(1u, active_interval.size()); - EXPECT_LT(active_interval[0].start, start_time); - EXPECT_GT(active_interval[0].end, start_time); -} - -TEST(PerformanceMonitorDatabaseSetupTest, - ActiveIntervalRetrievalAfterActiveInterval) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - TestingClock* clock = new TestingClock(); - scoped_ptr<Database> db = Database::Create(temp_dir.path()); - db->set_clock(scoped_ptr<Database::Clock>(clock)); - db->AddStateValue("test", "test"); - - base::Time start_time = clock->GetTime(); - base::Time end_time = clock->GetTime(); - std::vector<TimeRange> active_interval = db->GetActiveIntervals(start_time, - end_time); - EXPECT_TRUE(active_interval.empty()); -} - -////// PerformanceMonitorDatabaseEventTests //////////////////////////////////// -TEST_F(PerformanceMonitorDatabaseEventTest, GetAllEvents) { - Database::EventVector events = db_->GetEvents(); - ASSERT_EQ(4u, events.size()); - EXPECT_TRUE(events[0]->data()->Equals(install_event_1_->data())); - EXPECT_TRUE(events[1]->data()->Equals(install_event_2_->data())); - EXPECT_TRUE(events[2]->data()->Equals(uninstall_event_1_->data())); - EXPECT_TRUE(events[3]->data()->Equals(uninstall_event_2_->data())); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetMaxMetric) { - Metric stat; - EXPECT_EQ(0.0, db_->GetMaxStatsForActivityAndMetric(activity_, - METRIC_PAGE_LOAD_TIME)); - - EXPECT_EQ(1000000, - db_->GetMaxStatsForActivityAndMetric(METRIC_PRIVATE_MEMORY_USAGE)); - - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_PRIVATE_MEMORY_USAGE, clock_->GetTime(), 99.0)); - EXPECT_EQ(1000000, - db_->GetMaxStatsForActivityAndMetric(METRIC_PRIVATE_MEMORY_USAGE)); - - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_PRIVATE_MEMORY_USAGE, - clock_->GetTime(), - 6000000.0)); - EXPECT_EQ(6000000, - db_->GetMaxStatsForActivityAndMetric(METRIC_PRIVATE_MEMORY_USAGE)); -} - -TEST_F(PerformanceMonitorDatabaseEventTest, GetAllEventTypes) { - Database::EventTypeSet types = db_->GetEventTypes(); - ASSERT_EQ(2u, types.size()); - ASSERT_EQ(1u, types.count(EVENT_EXTENSION_INSTALL)); - ASSERT_EQ(1u, types.count(EVENT_EXTENSION_UNINSTALL)); -} - -TEST_F(PerformanceMonitorDatabaseEventTest, GetEventInTimeRange) { - base::Time start_time = clock_->GetTime(); - scoped_ptr<Event> crash_event = util::CreateRendererFailureEvent( - clock_->GetTime(), EVENT_RENDERER_CRASH, "http://www.google.com/"); - db_->AddEvent(*crash_event.get()); - Database::EventVector events = db_->GetEvents(start_time, clock_->GetTime()); - ASSERT_EQ(1u, events.size()); - EXPECT_TRUE(events[0]->data()->Equals(crash_event->data())); -} - -TEST_F(PerformanceMonitorDatabaseEventTest, GetInstallEvents) { - Database::EventVector events = db_->GetEvents(EVENT_EXTENSION_INSTALL); - ASSERT_EQ(2u, events.size()); - EXPECT_TRUE(events[0]->data()->Equals(install_event_1_->data())); - EXPECT_TRUE(events[1]->data()->Equals(install_event_2_->data())); -} - -TEST_F(PerformanceMonitorDatabaseEventTest, InvalidEvents) { - DatabaseTestHelper helper(db_.get()); - - // Insert an invalid event into the database; verify it is inserted. - size_t original_number_of_entries = helper.GetNumberOfEventEntries(); - ASSERT_TRUE(helper.AddInvalidEvent( - clock_->GetTime(), EVENT_EXTENSION_INSTALL)); - ASSERT_EQ(original_number_of_entries + 1u, helper.GetNumberOfEventEntries()); - - // Should not retrieve the invalid event. - Database::EventVector events = db_->GetEvents(); - ASSERT_EQ(original_number_of_entries, events.size()); - - // Invalid event should have been deleted. - ASSERT_EQ(original_number_of_entries, helper.GetNumberOfEventEntries()); -} - -TEST_F(PerformanceMonitorDatabaseEventTest, GetUnusedEventType) { - Database::EventVector events = db_->GetEvents(EVENT_EXTENSION_DISABLE); - ASSERT_TRUE(events.empty()); - events = db_->GetEvents(EVENT_EXTENSION_DISABLE, clock_->GetTime(), - clock_->GetTime()); - ASSERT_TRUE(events.empty()); -} - -TEST_F(PerformanceMonitorDatabaseEventTest, GetEventsTimeRange) { - base::Time start_time = clock_->GetTime(); - scoped_ptr<Event> new_install_event = - util::CreateExtensionEvent(EVENT_EXTENSION_INSTALL, clock_->GetTime(), - "c", "test extension", "http://foo.com", - static_cast<int>(Manifest::UNPACKED), "0.1", - "Test Test"); - scoped_ptr<Event> new_uninstall_event = - util::CreateExtensionEvent(EVENT_EXTENSION_UNINSTALL, clock_->GetTime(), - "c", "test extension", "http://foo.com", - static_cast<int>(Manifest::UNPACKED), "0.1", - "Test Test"); - base::Time end_time = clock_->GetTime(); - db_->AddEvent(*new_install_event.get()); - db_->AddEvent(*new_uninstall_event.get()); - Database::EventVector events = db_->GetEvents(start_time, end_time); - ASSERT_EQ(2u, events.size()); - EXPECT_TRUE(events[0]->data()->Equals(new_install_event->data())); - EXPECT_TRUE(events[1]->data()->Equals(new_uninstall_event->data())); - events = db_->GetEvents( - EVENT_EXTENSION_INSTALL, start_time, end_time); - ASSERT_EQ(1u, events.size()); - EXPECT_TRUE(events[0]->data()->Equals(new_install_event->data())); -} - -////// PerformanceMonitorDatabaseMetricTests /////////////////////////////////// -TEST_F(PerformanceMonitorDatabaseMetricTest, GetActiveMetrics) { - Database::MetricTypeSet active_metrics = - db_->GetActiveMetrics(base::Time(), clock_->GetTime()); - - Database::MetricTypeSet expected_metrics; - expected_metrics.insert(METRIC_CPU_USAGE); - expected_metrics.insert(METRIC_PRIVATE_MEMORY_USAGE); - EXPECT_EQ(expected_metrics, active_metrics); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetRecentMetric) { - Metric stat; - ASSERT_TRUE(db_->GetRecentStatsForActivityAndMetric(activity_, - METRIC_PRIVATE_MEMORY_USAGE, &stat)); - EXPECT_EQ(3000000, stat.value); - - ASSERT_TRUE(db_->GetRecentStatsForActivityAndMetric(METRIC_CPU_USAGE, &stat)); - EXPECT_EQ(50.5, stat.value); - - base::ScopedTempDir dir; - CHECK(dir.CreateUniqueTempDir()); - scoped_ptr<Database> db = Database::Create(dir.path()); - CHECK(db.get()); - db->set_clock(scoped_ptr<Database::Clock>(new TestingClock())); - EXPECT_FALSE(db->GetRecentStatsForActivityAndMetric(METRIC_CPU_USAGE, &stat)); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetState) { - std::string key("version"); - std::string value("1.0.0.0.1"); - db_->AddStateValue(key, value); - EXPECT_EQ(db_->GetStateValue(key), value); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetStateOverride) { - std::string key("version"); - std::string value_1("1.0.0.0.0"); - std::string value_2("1.0.0.0.1"); - db_->AddStateValue(key, value_1); - db_->AddStateValue(key, value_2); - EXPECT_EQ(db_->GetStateValue(key), value_2); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetStatsForActivityAndMetric) { - Database::MetricVector stats = *db_->GetStatsForActivityAndMetric( - activity_, METRIC_CPU_USAGE, base::Time(), clock_->GetTime()); - ASSERT_EQ(1u, stats.size()); - EXPECT_EQ(13.1, stats[0].value); - base::Time before = clock_->GetTime(); - db_->AddMetric(activity_, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 18.0)); - stats = *db_->GetStatsForActivityAndMetric(activity_, METRIC_CPU_USAGE, - before, clock_->GetTime()); - ASSERT_EQ(1u, stats.size()); - EXPECT_EQ(18, stats[0].value); - stats = *db_->GetStatsForActivityAndMetric(activity_, METRIC_CPU_USAGE); - ASSERT_EQ(2u, stats.size()); - EXPECT_EQ(13.1, stats[0].value); - EXPECT_EQ(18, stats[1].value); - stats = *db_->GetStatsForActivityAndMetric(METRIC_PRIVATE_MEMORY_USAGE); - ASSERT_EQ(1u, stats.size()); - EXPECT_EQ(1000000, stats[0].value); - stats = *db_->GetStatsForActivityAndMetric(activity_, METRIC_CPU_USAGE, - clock_->GetTime(), - clock_->GetTime()); - EXPECT_TRUE(stats.empty()); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetStatsForMetricByActivity) { - Database::MetricVectorMap stats_map = db_->GetStatsForMetricByActivity( - METRIC_CPU_USAGE, base::Time(), clock_->GetTime()); - ASSERT_EQ(2u, stats_map.size()); - linked_ptr<Database::MetricVector> stats = stats_map[activity_]; - ASSERT_EQ(1u, stats->size()); - EXPECT_EQ(13.1, stats->at(0).value); - stats = stats_map[kProcessChromeAggregate]; - ASSERT_EQ(1u, stats->size()); - EXPECT_EQ(50.5, stats->at(0).value); - stats_map = db_->GetStatsForMetricByActivity( - METRIC_CPU_USAGE, clock_->GetTime(), clock_->GetTime()); - EXPECT_EQ(0u, stats_map.size()); - base::Time before = clock_->GetTime(); - db_->AddMetric(activity_, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 18.0)); - stats_map = db_->GetStatsForMetricByActivity(METRIC_CPU_USAGE, before, - clock_->GetTime()); - ASSERT_EQ(1u, stats_map.size()); - stats = stats_map[activity_]; - ASSERT_EQ(1u, stats->size()); - EXPECT_EQ(18, stats->at(0).value); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, InvalidMetrics) { - DatabaseTestHelper helper(db_.get()); - Metric invalid_metric(METRIC_CPU_USAGE, clock_->GetTime(), -5.0); - ASSERT_FALSE(invalid_metric.IsValid()); - - // Find the original number of entries in the database. - size_t original_number_of_entries = helper.GetNumberOfMetricEntries(); - Database::MetricVector stats = *db_->GetStatsForActivityAndMetric( - activity_, METRIC_CPU_USAGE, base::Time(), clock_->GetTime()); - size_t original_number_of_cpu_entries = stats.size(); - - // Check that the database normally refuses to insert bad metrics. - EXPECT_FALSE(db_->AddMetric(invalid_metric)); - - // Verify that it was not inserted into the database. - stats = *db_->GetStatsForActivityAndMetric( - activity_, METRIC_CPU_USAGE, base::Time(), clock_->GetTime()); - ASSERT_EQ(original_number_of_cpu_entries, stats.size()); - - // Forcefully insert it into the database. - ASSERT_TRUE(helper.AddInvalidMetric(activity_, invalid_metric)); - ASSERT_EQ(original_number_of_entries + 1u, helper.GetNumberOfMetricEntries()); - - // Try to retrieve it; should only get one result. - stats = *db_->GetStatsForActivityAndMetric( - activity_, METRIC_CPU_USAGE, base::Time(), clock_->GetTime()); - ASSERT_EQ(original_number_of_cpu_entries, stats.size()); - - // Entry should have been deleted in the database. - ASSERT_EQ(original_number_of_entries, helper.GetNumberOfMetricEntries()); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetFullRange) { - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 3.4)); - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 21.0)); - Database::MetricVector stats = - *db_->GetStatsForActivityAndMetric(METRIC_CPU_USAGE); - ASSERT_EQ(3u, stats.size()); - ASSERT_EQ(50.5, stats[0].value); - ASSERT_EQ(3.4, stats[1].value); - ASSERT_EQ(21, stats[2].value); -} - -TEST_F(PerformanceMonitorDatabaseMetricTest, GetRange) { - base::Time start = clock_->GetTime(); - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 3.0)); - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 9.0)); - base::Time end = clock_->GetTime(); - db_->AddMetric(kProcessChromeAggregate, - Metric(METRIC_CPU_USAGE, clock_->GetTime(), 21.0)); - Database::MetricVector stats = - *db_->GetStatsForActivityAndMetric(METRIC_CPU_USAGE, start, end); - ASSERT_EQ(2u, stats.size()); - ASSERT_EQ(3, stats[0].value); - ASSERT_EQ(9, stats[1].value); -} - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/event.cc b/chrome/browser/performance_monitor/event.cc deleted file mode 100644 index 46b48b9..0000000 --- a/chrome/browser/performance_monitor/event.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/event.h" - -#include "base/logging.h" - -namespace performance_monitor { - -Event::Event(const EventType& type, - const base::Time& time, - scoped_ptr<base::DictionaryValue> data) - : type_(type), time_(time), data_(data.release()) { -} - -Event::~Event() { -} - -scoped_ptr<Event> Event::FromValue(scoped_ptr<base::DictionaryValue> data) { - int type = 0; - if (!data->GetInteger(std::string("eventType"), &type)) - return scoped_ptr<Event>(); - double time = 0.0; - if (!data->GetDouble(std::string("time"), &time)) - return scoped_ptr<Event>(); - return scoped_ptr<Event>(new Event(static_cast<EventType>(type), - base::Time::FromInternalValue((int64)time), - data.Pass())); -} - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/event.h b/chrome/browser/performance_monitor/event.h deleted file mode 100644 index 4bde259..0000000 --- a/chrome/browser/performance_monitor/event.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_H_ - -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" -#include "base/values.h" - -#include "chrome/browser/performance_monitor/event_type.h" - -namespace performance_monitor { - -const char* EventTypeToString(EventType event_type); - -// The wrapper class for the JSON-generated event classes for the performance -// monitor. This class is used so we can pass around events in a single class, -// rather than having a variety of different types (since JSON does not -// currently support inheritance). Since the class will occasionally need to -// be compared against other events, we construct it with type and time. Other -// information should not be needed commonly, and is stored in a JSON-generated -// DictionaryValue. -class Event { - public: - Event(const EventType& type, - const base::Time& time, - scoped_ptr<base::DictionaryValue> data); - virtual ~Event(); - - // Construct an event from the given DictionaryValue; takes ownership of - // |data|. - static scoped_ptr<Event> FromValue(scoped_ptr<base::DictionaryValue> data); - - // Accessors - EventType type() const { return type_; } - base::Time time() const { return time_; } - base::DictionaryValue* data() const { return data_.get(); } - - private: - - // The type of the event. - EventType type_; - // The time at which the event was recorded. - base::Time time_; - // The full JSON-generated value representing the information of the event; - // these data are described in chrome/browser/performance_monitor/events.json. - scoped_ptr<base::DictionaryValue> data_; -}; - -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_H_ diff --git a/chrome/browser/performance_monitor/event_type.h b/chrome/browser/performance_monitor/event_type.h deleted file mode 100644 index fd19cac..0000000 --- a/chrome/browser/performance_monitor/event_type.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_TYPE_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_TYPE_H_ - -namespace performance_monitor { - -// IMPORTANT: To add new events, please -// - Place the new event above EVENT_NUMBER_OF_EVENTS. -// - Add a member to the EventKeyChar enum in key_builder.cc. -// - Add the appropriate messages in generated_resources.grd. -// - Add the appropriate functions in -// chrome/browser/ui/webui/performance_monitor/performance_monitor_l10n.h. -enum EventType { - EVENT_UNDEFINED, - - // Extension-Related events - EVENT_EXTENSION_INSTALL, - EVENT_EXTENSION_UNINSTALL, - EVENT_EXTENSION_UPDATE, - EVENT_EXTENSION_ENABLE, - EVENT_EXTENSION_DISABLE, - - // Chrome's version has changed. - EVENT_CHROME_UPDATE, - - // Renderer-Failure related events; these correspond to the RENDERER_HANG - // event, and the two termination statuses ABNORMAL_EXIT and PROCESS_KILLED, - // respectively. - EVENT_RENDERER_HANG, - EVENT_RENDERER_CRASH, - EVENT_RENDERER_KILLED, - - // Chrome did not shut down correctly. - EVENT_UNCLEAN_EXIT, - - EVENT_NUMBER_OF_EVENTS -}; - -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_TYPE_H_ diff --git a/chrome/browser/performance_monitor/events.json b/chrome/browser/performance_monitor/events.json deleted file mode 100644 index 3b04c35..0000000 --- a/chrome/browser/performance_monitor/events.json +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -[ - { - "namespace": "events", - "description": "Performance monitor events", - "types": [ - { - "id": "ExtensionEvent", - "type": "object", - "description": "The event to describe a significant occurrence with an extension in Chrome, including installation, uninstallation, enablement, disablement, and update.", - "properties": { - "eventType": {"type": "integer", "description": "The type of the event."}, - "time": {"type": "number", "description": "The time at which the event was recorded."}, - "extensionId": {"type": "string", "description": "The extension's id."}, - "extensionName": {"type": "string", "description": "The extension's name."}, - "extensionUrl": {"type": "string", "description": "The extension's url."}, - "extensionLocation": {"type": "integer", "description": "The extension's install location."}, - "extensionVersion": {"type": "string", "description": "The string reprepresentation of the extension's version."}, - "extensionDescription": {"type": "string", "description": "The extension's description."} - } - }, - { - "id": "ChromeUpdate", - "type": "object", - "description": "The event to describe an update to Chrome; this will be recognized on startup by a change in the version number.", - "properties": { - "eventType": {"type": "integer", "description": "The type of the event."}, - "time": {"type": "number", "description": "The time at which the event was recorded."}, - "previousVersion": {"type": "string", "description": "The string representation of the previous Chrome version."}, - "currentVersion": {"type": "string", "description": "The string representation of the current Chrome version."} - } - }, - { - "id": "RendererFailure", - "type": "object", - "description": "The event to represent a renderer hanging, crashing, or being killed.", - "properties": { - "eventType": {"type": "integer", "description": "The type of the event."}, - "time": {"type": "number", "description": "The time at which the event was recorded."}, - "url": {"type": "string", "description": "The url (or urls) associated with the renderer failure, if available (if unavailable, this is empty)."} - } - }, - { - "id": "UncleanExit", - "type": "object", - "description": "The event to represent an unclean exit.", - "properties": { - "eventType": {"type": "integer", "description": "The type of the event."}, - "time": {"type": "number", "description": "The time at which the event was recorded."}, - "profileName": {"type": "string", "description": "The name of the profile which shutdown uncleanly."} - } - } - ] - } -] diff --git a/chrome/browser/performance_monitor/key_builder.cc b/chrome/browser/performance_monitor/key_builder.cc deleted file mode 100644 index 64dc94e..0000000 --- a/chrome/browser/performance_monitor/key_builder.cc +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/key_builder.h" - -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/stringprintf.h" - -namespace performance_monitor { - -namespace { - -const char kDelimiter = '!'; - -// These values are used as the portion of the generated key which represents -// the event/metric type when inserting values in the database. We use an ASCII -// character as a mapping, rather than the enum of the metric or event itself, -// so that we can edit the MetricType and EventType enums as desired, without -// worrying about the integrity of the database. -// -// Once a character mapping has been set for a metric or event, do not change -// its value! New character mappings should be greater than 34 (ASCII characters -// below 32 have meaning, 33 is '!' - the database delimiter, and 34 is reserved -// for the 'Undefined' character mapping). Do not repeat values within the -// metric/event sets (repeated values between sets are okay). -// -// Deprecated keys: A key which is deprecated should be clearly marked as such, -// and its use discontinued. Do not remove the key from the listing! (Otherwise, -// a new metric may take its key and think the old data belongs to it.) - -enum MetricKeyChar { -METRIC_UNDEFINED_KEY_CHAR = 34, -METRIC_CPU_USAGE_KEY_CHAR = 35, -METRIC_PRIVATE_MEMORY_USAGE_KEY_CHAR = 36, -METRIC_SHARED_MEMORY_USAGE_KEY_CHAR = 37, -METRIC_STARTUP_TIME_KEY_CHAR = 38, -METRIC_TEST_STARTUP_TIME_KEY_CHAR = 39, -METRIC_SESSION_RESTORE_TIME_KEY_CHAR = 40, -METRIC_PAGE_LOAD_TIME_KEY_CHAR = 41, -METRIC_NETWORK_BYTES_READ_KEY_CHAR = 42, -METRIC_NUMBER_OF_METRICS_KEY_CHAR = 255, -}; - -enum EventKeyChar { -EVENT_UNDEFINED_KEY_CHAR = 34, -EVENT_EXTENSION_INSTALL_KEY_CHAR = 35, -EVENT_EXTENSION_UNINSTALL_KEY_CHAR = 36, -EVENT_EXTENSION_UPDATE_KEY_CHAR = 37, -EVENT_EXTENSION_ENABLE_KEY_CHAR = 38, -EVENT_EXTENSION_DISABLE_KEY_CHAR = 39, -EVENT_CHROME_UPDATE_KEY_CHAR = 40, -EVENT_RENDERER_HANG_KEY_CHAR = 41, -EVENT_RENDERER_CRASH_KEY_CHAR = 42, -EVENT_RENDERER_KILLED_KEY_CHAR = 43, -EVENT_UNCLEAN_EXIT_KEY_CHAR = 44, -EVENT_NUMBER_OF_EVENTS_KEY_CHAR = 255, -}; - -// The position of different elements in the key for the event db. -enum EventKeyPosition { - EVENT_TIME, // The time the event was generated. - EVENT_TYPE // The type of event. -}; - -// The position of different elements in the key for the recent db. -enum RecentKeyPosition { - RECENT_TIME, // The time the stat was gathered. - RECENT_TYPE, // The unique identifier for the type of metric gathered. - RECENT_ACTIVITY // The unique identifier for the activity. -}; - -// The position of different elements in the key for the max value db. -enum MaxValueKeyPosition { - MAX_VALUE_TYPE, // The unique identifier for the type of metric gathered. - MAX_VALUE_ACTIVITY // The unique identifier for the activity. -}; - -// The position of different elements in the key for a metric db. -enum MetricKeyPosition { - METRIC_TYPE, // The unique identifier for the metric. - METRIC_TIME, // The time the stat was gathered. - METRIC_ACTIVITY // The unique identifier for the activity. -}; - -} // namespace - -RecentKey::RecentKey(const std::string& recent_time, - MetricType recent_type, - const std::string& recent_activity) - : time(recent_time), type(recent_type), activity(recent_activity) { -} - -RecentKey::~RecentKey() { -} - -MetricKey::MetricKey(const std::string& metric_time, - MetricType metric_type, - const std::string& metric_activity) - : time(metric_time), type(metric_type), activity(metric_activity) { -} - -MetricKey::~MetricKey() { -} - -KeyBuilder::KeyBuilder() { - PopulateKeyMaps(); -} - -KeyBuilder::~KeyBuilder() { -} - -void KeyBuilder::PopulateKeyMaps() { - // Hard-code the generation of the map between event types and event key - // character mappings. - event_type_to_event_key_char_[EVENT_UNDEFINED] = EVENT_UNDEFINED_KEY_CHAR; - event_type_to_event_key_char_[EVENT_EXTENSION_INSTALL] = - EVENT_EXTENSION_INSTALL_KEY_CHAR; - event_type_to_event_key_char_[EVENT_EXTENSION_UNINSTALL] = - EVENT_EXTENSION_UNINSTALL_KEY_CHAR; - event_type_to_event_key_char_[EVENT_EXTENSION_UPDATE] = - EVENT_EXTENSION_UPDATE_KEY_CHAR; - event_type_to_event_key_char_[EVENT_EXTENSION_ENABLE] = - EVENT_EXTENSION_ENABLE_KEY_CHAR; - event_type_to_event_key_char_[EVENT_EXTENSION_DISABLE] = - EVENT_EXTENSION_DISABLE_KEY_CHAR; - event_type_to_event_key_char_[EVENT_RENDERER_HANG] = - EVENT_RENDERER_HANG_KEY_CHAR; - event_type_to_event_key_char_[EVENT_RENDERER_CRASH] = - EVENT_RENDERER_CRASH_KEY_CHAR; - event_type_to_event_key_char_[EVENT_RENDERER_KILLED] = - EVENT_RENDERER_KILLED_KEY_CHAR; - event_type_to_event_key_char_[EVENT_UNCLEAN_EXIT] = - EVENT_UNCLEAN_EXIT_KEY_CHAR; - event_type_to_event_key_char_[EVENT_NUMBER_OF_EVENTS] = - EVENT_NUMBER_OF_EVENTS_KEY_CHAR; - DCHECK(event_type_to_event_key_char_.size() == EVENT_NUMBER_OF_EVENTS); - - // Generate the reverse map for easy look-up between event character mappings - // and event types. - for (int i = static_cast<int>(EVENT_UNDEFINED); - i <= static_cast<int>(EVENT_NUMBER_OF_EVENTS); ++i) { - event_key_char_to_event_type_[event_type_to_event_key_char_[ - static_cast<EventType>(i)]] = static_cast<EventType>(i); - } - - // Repeat the process for metrics. - metric_type_to_metric_key_char_[METRIC_UNDEFINED] = METRIC_UNDEFINED_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_CPU_USAGE] = METRIC_CPU_USAGE_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_PRIVATE_MEMORY_USAGE] = - METRIC_PRIVATE_MEMORY_USAGE_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_SHARED_MEMORY_USAGE] = - METRIC_SHARED_MEMORY_USAGE_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_STARTUP_TIME] = - METRIC_STARTUP_TIME_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_TEST_STARTUP_TIME] = - METRIC_TEST_STARTUP_TIME_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_PAGE_LOAD_TIME] = - METRIC_PAGE_LOAD_TIME_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_NETWORK_BYTES_READ] = - METRIC_NETWORK_BYTES_READ_KEY_CHAR; - metric_type_to_metric_key_char_[METRIC_NUMBER_OF_METRICS] = - METRIC_NUMBER_OF_METRICS_KEY_CHAR; - DCHECK(metric_type_to_metric_key_char_.size() == METRIC_NUMBER_OF_METRICS); - - for (int i = static_cast<int>(METRIC_UNDEFINED); - i <= static_cast<int>(METRIC_NUMBER_OF_METRICS); ++i) { - metric_key_char_to_metric_type_[metric_type_to_metric_key_char_[ - static_cast<MetricType>(i)]] = static_cast<MetricType>(i); - } -} - -std::string KeyBuilder::CreateActiveIntervalKey(const base::Time& time) { - return base::StringPrintf("%016" PRId64, time.ToInternalValue()); -} - -std::string KeyBuilder::CreateMetricKey(const base::Time& time, - const MetricType type, - const std::string& activity) { - return base::StringPrintf("%c%c%016" PRId64 "%c%s", - metric_type_to_metric_key_char_[type], - kDelimiter, time.ToInternalValue(), - kDelimiter, activity.c_str()); -} - -std::string KeyBuilder::CreateEventKey(const base::Time& time, - const EventType type) { - return base::StringPrintf("%016" PRId64 "%c%c", - time.ToInternalValue(), kDelimiter, - event_type_to_event_key_char_[type]); -} - -std::string KeyBuilder::CreateRecentKey(const base::Time& time, - const MetricType type, - const std::string& activity) { - return base::StringPrintf("%016" PRId64 "%c%c%c%s", - time.ToInternalValue(), - kDelimiter, metric_type_to_metric_key_char_[type], - kDelimiter, activity.c_str()); -} - -std::string KeyBuilder::CreateRecentMapKey(const MetricType type, - const std::string& activity) { - return base::StringPrintf("%s%c%c", - activity.c_str(), - kDelimiter, metric_type_to_metric_key_char_[type]); -} - -std::string KeyBuilder::CreateMaxValueKey(const MetricType type, - const std::string& activity) { - return base::StringPrintf("%c%c%s", - metric_type_to_metric_key_char_[type], - kDelimiter, activity.c_str()); -} - -EventType KeyBuilder::EventKeyToEventType(const std::string& event_key) { - std::vector<std::string> split; - base::SplitString(event_key, kDelimiter, &split); - DCHECK(split[EVENT_TYPE].size() == 1); - return event_key_char_to_event_type_[ - static_cast<int>(split[EVENT_TYPE].at(0))]; -} - -RecentKey KeyBuilder::SplitRecentKey(const std::string& key) { - std::vector<std::string> split; - base::SplitString(key, kDelimiter, &split); - DCHECK(split[RECENT_TYPE].size() == 1); - return RecentKey(split[RECENT_TIME], - metric_key_char_to_metric_type_[ - static_cast<int>(split[RECENT_TYPE].at(0))], - split[RECENT_ACTIVITY]); -} - -MetricKey KeyBuilder::SplitMetricKey(const std::string& key) { - std::vector<std::string> split; - base::SplitString(key, kDelimiter, &split); - DCHECK(split[METRIC_TYPE].size() == 1); - return MetricKey(split[METRIC_TIME], - metric_key_char_to_metric_type_[ - static_cast<int>(split[METRIC_TYPE].at(0))], - split[METRIC_ACTIVITY]); -} - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/key_builder.h b/chrome/browser/performance_monitor/key_builder.h deleted file mode 100644 index 1b4ac24..0000000 --- a/chrome/browser/performance_monitor/key_builder.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_KEY_BUILDER_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_KEY_BUILDER_H_ - -#include <map> - -#include "chrome/browser/performance_monitor/event.h" -#include "chrome/browser/performance_monitor/metric.h" - -namespace performance_monitor { - -struct RecentKey { - RecentKey(const std::string& recent_time, - MetricType recent_type, - const std::string& recent_activity); - ~RecentKey(); - - const std::string time; - const MetricType type; - const std::string activity; -}; - -struct MaxValueKey { - MaxValueKey(MetricType max_value_type, - const std::string& max_value_activity) - : type(max_value_type), - activity(max_value_activity) {} - ~MaxValueKey() {} - - const MetricType type; - const std::string activity; -}; - -struct MetricKey { - MetricKey(const std::string& metric_time, - MetricType metric_type, - const std::string& metric_activity); - ~MetricKey(); - - const std::string time; - const MetricType type; - const std::string activity; -}; - -// This class is responsible for building the keys which are used internally by -// PerformanceMonitor's database. These keys should only be referenced by the -// database, and should not be used externally. -class KeyBuilder { - public: - KeyBuilder(); - ~KeyBuilder(); - - // Key Creation: Create the keys for different databases. The schemas are - // listed with the methods. A '-' in the schema represents kDelimeter. - - // Key Schema: <Time> - std::string CreateActiveIntervalKey(const base::Time& time); - - // Key Schema: <Metric>-<Time>-<Activity> - std::string CreateMetricKey(const base::Time& time, - const MetricType type, - const std::string& activity); - - // Key Schema: <Time>-<Event Type> - std::string CreateEventKey(const base::Time& time, const EventType type); - - // Key Schema: <Time>-<Metric>-<Activity> - std::string CreateRecentKey(const base::Time& time, - const MetricType type, - const std::string& activity); - - // Key Schema: <Activity>-<Metric> - std::string CreateRecentMapKey(const MetricType type, - const std::string& activity); - - std::string CreateMaxValueKey(const MetricType type, - const std::string& activity); - - EventType EventKeyToEventType(const std::string& key); - RecentKey SplitRecentKey(const std::string& key); - MetricKey SplitMetricKey(const std::string& key); - - private: - // Populate the maps from [Event, Metric]Type to key characters. - void PopulateKeyMaps(); - - std::map<EventType, int> event_type_to_event_key_char_; - std::map<int, EventType> event_key_char_to_event_type_; - std::map<MetricType, int> metric_type_to_metric_key_char_; - std::map<int, MetricType> metric_key_char_to_metric_type_; -}; - -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_KEY_BUILDER_H_ diff --git a/chrome/browser/performance_monitor/metric.cc b/chrome/browser/performance_monitor/metric.cc deleted file mode 100644 index 2699c41..0000000 --- a/chrome/browser/performance_monitor/metric.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/metric.h" - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/time/time.h" -#include "chrome/browser/performance_monitor/constants.h" - -namespace performance_monitor { - -namespace { - -// For certain metrics (for instance, bytes read), it is possible that there is -// no maximum value which we can safely assume. -const double kNoMaximum = -1.0; - -// These constants are designed to keep metrics reasonable. However, due to the -// variety of system configurations which can run chrome, these values may not -// catch *all* erroneous values. For instance, on a one-CPU machine, any CPU -// usage > 100 is erroneous, but on a 16-CPU machine, it's perfectly normal. -// These are "best-guesses" in order to weed out obviously-false values. A -// metric is valid if it is greater than or equal to the minimum and less than -// the maximum, i.e. if it falls in the range [min, max). -const double kMinUndefined = 0.0; -const double kMaxUndefined = 0.0; // No undefined metric is valid. -const double kMinCpuUsage = 0.0; -const double kMaxCpuUsage = 100000.0; // 100% on a 1000-CPU machine. -const double kMinPrivateMemoryUsage = 0.0; -const double kMaxPrivateMemoryUsage = kBytesPerTerabyte; -const double kMinSharedMemoryUsage = 0.0; -const double kMaxSharedMemoryUsage = kBytesPerTerabyte; -const double kMinStartupTime = 0.0; -const double kMaxStartupTime = base::Time::kMicrosecondsPerMinute * 15.0; -const double kMinTestStartupTime = 0.0; -const double kMaxTestStartupTime = base::Time::kMicrosecondsPerMinute * 15.0; -const double kMinSessionRestoreTime = 0.0; -const double kMaxSessionRestoreTime = base::Time::kMicrosecondsPerMinute * 15.0; -const double kMinPageLoadTime = 0.0; -const double kMaxPageLoadTime = base::Time::kMicrosecondsPerMinute * 15.0; -const double kMinNetworkBytesRead = 0.0; -const double kMaxNetworkBytesRead = kNoMaximum; - -struct MetricBound { - double min; - double max; -}; - -const MetricBound kMetricBounds[] = { - { kMinUndefined, kMaxUndefined }, - { kMinCpuUsage, kMaxCpuUsage }, - { kMinPrivateMemoryUsage, kMaxPrivateMemoryUsage }, - { kMinSharedMemoryUsage, kMaxSharedMemoryUsage }, - { kMinStartupTime, kMaxStartupTime }, - { kMinTestStartupTime, kMaxTestStartupTime }, - { kMinSessionRestoreTime, kMaxSessionRestoreTime }, - { kMinPageLoadTime, kMaxPageLoadTime }, - { kMinNetworkBytesRead, kMaxNetworkBytesRead }, -}; - -COMPILE_ASSERT(ARRAYSIZE_UNSAFE(kMetricBounds) == METRIC_NUMBER_OF_METRICS, - metric_bounds_size_doesnt_match_metric_count); - -} // namespace - -Metric::Metric() : type(METRIC_UNDEFINED), value(0.0) { -} - -Metric::Metric(MetricType metric_type, - const base::Time& metric_time, - const double metric_value) - : type(metric_type), time(metric_time), value(metric_value) { -} - -Metric::Metric(MetricType metric_type, - const std::string& metric_time, - const std::string& metric_value) : type(metric_type) { - int64 conversion = 0; - base::StringToInt64(metric_time, &conversion); - time = base::Time::FromInternalValue(conversion); - CHECK(base::StringToDouble(metric_value, &value)); -} - -Metric::~Metric() { -} - -bool Metric::IsValid() const { - return type < METRIC_NUMBER_OF_METRICS && - (value < kMetricBounds[type].max || - kMetricBounds[type].max == kNoMaximum) && - value >= kMetricBounds[type].min; -} - -std::string Metric::ValueAsString() const { - return base::DoubleToString(value); -} - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/metric.h b/chrome/browser/performance_monitor/metric.h deleted file mode 100644 index ab9da9f..0000000 --- a/chrome/browser/performance_monitor/metric.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_METRIC_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_METRIC_H_ - -#include <string> -#include "base/time/time.h" - -namespace performance_monitor { - -// IMPORTANT: To add new metrics, please -// - Place the new metric above METRIC_NUMBER_OF_METRICS. -// - Add a member to the MetricKeyChar enum in key_builder.cc. -// - Add the appropriate messages in generated_resources.grd. -// - Add the appropriate functions in -// chrome/browser/ui/webui/performance_monitor/performance_monitor_l10n.h. -enum MetricType { - METRIC_UNDEFINED, - - // CPU and memory usage are combined for all Chrome-related processes. - METRIC_CPU_USAGE, - METRIC_PRIVATE_MEMORY_USAGE, - METRIC_SHARED_MEMORY_USAGE, - - // Timing measurements; these are all independent metrics (e.g., session - // restore time is independent of startup time, even though they may happen - // in sequence). Test startup time refers to any non-normal startup time, e.g. - // when we run test suites. - METRIC_STARTUP_TIME, - METRIC_TEST_STARTUP_TIME, - METRIC_SESSION_RESTORE_TIME, - METRIC_PAGE_LOAD_TIME, - - // Total number of bytes read since PerformanceMonitor first started running. - METRIC_NETWORK_BYTES_READ, - - METRIC_NUMBER_OF_METRICS -}; - -struct Metric { - public: - Metric(); - Metric(MetricType metric_type, - const base::Time& metric_time, - const double metric_value); - Metric(MetricType metric_type, - const std::string& metric_time, - const std::string& metric_value); - ~Metric(); - - // Check the value in the metric to make sure that it is reasonable. Since - // some metric-gathering methods will fail and return incorrect values, we - // need to try to weed these out as best we can. - bool IsValid() const; - - // This converts the double stored in value to a string format. This will - // not perform any checking on the validity of the metric, and only makes - // sense if the metric IsValid(). - std::string ValueAsString() const; - - MetricType type; - base::Time time; - double value; -}; - -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_METRIC_H_ diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc index 87086d6..3e2cfdb 100644 --- a/chrome/browser/performance_monitor/performance_monitor.cc +++ b/chrome/browser/performance_monitor/performance_monitor.cc @@ -4,130 +4,30 @@ #include "chrome/browser/performance_monitor/performance_monitor.h" -#include <set> -#include <vector> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/logging.h" #include "base/memory/singleton.h" #include "base/process/process_iterator.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/threading/worker_pool.h" #include "base/time/time.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_shutdown.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/performance_monitor/constants.h" -#include "chrome/browser/performance_monitor/performance_monitor_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_iterator.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/chrome_version_info.h" #include "content/public/browser/browser_child_process_host.h" #include "content/public/browser/browser_child_process_host_iterator.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" -#include "content/public/browser/load_notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_types.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/render_widget_host_iterator.h" -#include "content/public/browser/web_contents.h" -#include "net/url_request/url_request.h" - -#if defined(ENABLE_EXTENSIONS) -#include "chrome/browser/extensions/crx_installer.h" -#include "chrome/common/extensions/extension_constants.h" -#include "extensions/common/extension.h" -#endif +#include "content/public/browser/render_process_host.h" using content::BrowserThread; -#if defined(ENABLE_EXTENSIONS) -using extensions::Extension; -using extensions::UnloadedExtensionInfo; -#endif - -namespace performance_monitor { - namespace { -#if !defined(OS_ANDROID) -std::string TimeToString(base::Time time) { - int64 time_int64 = time.ToInternalValue(); - return base::Int64ToString(time_int64); +// The default interval at which PerformanceMonitor performs its timed +// collections. +const int kGatherIntervalInSeconds = 120; } -#endif // !defined(OS_ANDROID) - -bool StringToTime(std::string time, base::Time* output) { - int64 time_int64 = 0; - if (!base::StringToInt64(time, &time_int64)) - return false; - *output = base::Time::FromInternalValue(time_int64); - return true; -} - -// Try to get the URL for the RenderViewHost if the host does not correspond to -// an incognito profile (we don't store URLs from incognito sessions). Returns -// true if url has been populated, and false otherwise. -bool MaybeGetURLFromRenderView(const content::RenderViewHost* view, - std::string* url) { - content::WebContents* web_contents = - content::WebContents::FromRenderViewHost(view); - - if (Profile::FromBrowserContext( - web_contents->GetBrowserContext())->IsOffTheRecord()) { - return false; - } - *url = web_contents->GetURL().spec(); - return true; -} - -// Takes ownership of and deletes |database| on the background thread, to -// avoid destruction in the middle of an operation. -void DeleteDatabaseOnBackgroundThread(Database* database) { - delete database; -} - -} // namespace - -bool PerformanceMonitor::initialized_ = false; - -PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread() - : network_bytes_read(0) { -} +namespace performance_monitor { -PerformanceMonitor::PerformanceMonitor() - : gather_interval_in_seconds_(kDefaultGatherIntervalInSeconds), - database_logging_enabled_(false), - timer_(FROM_HERE, - base::TimeDelta::FromSeconds(kSampleIntervalInSeconds), - this, - &PerformanceMonitor::DoTimedCollections), - disable_timer_autostart_for_testing_(false) { +PerformanceMonitor::PerformanceMonitor() { } PerformanceMonitor::~PerformanceMonitor() { - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&DeleteDatabaseOnBackgroundThread, database_.release())); -} - -bool PerformanceMonitor::SetDatabasePath(const base::FilePath& path) { - if (!database_.get()) { - database_path_ = path; - return true; - } - - // PerformanceMonitor already initialized with another path. - return false; } // static @@ -135,252 +35,17 @@ PerformanceMonitor* PerformanceMonitor::GetInstance() { return Singleton<PerformanceMonitor>::get(); } -void PerformanceMonitor::Initialize() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kPerformanceMonitorGathering)) { - database_logging_enabled_ = true; - - std::string switch_value = CommandLine::ForCurrentProcess()-> - GetSwitchValueASCII(switches::kPerformanceMonitorGathering); - - if (!switch_value.empty()) { - int specified_interval = 0; - if (!base::StringToInt(switch_value, &specified_interval) || - specified_interval <= 0) { - LOG(ERROR) << "Invalid value for switch: '" - << switches::kPerformanceMonitorGathering - << "'; please use an integer greater than 0."; - } else { - gather_interval_in_seconds_ = std::max(specified_interval, - kSampleIntervalInSeconds); - } - } - } - - DCHECK(gather_interval_in_seconds_ >= kSampleIntervalInSeconds); - - next_collection_time_ = base::Time::Now() + - base::TimeDelta::FromSeconds(gather_interval_in_seconds_); - - util::PostTaskToDatabaseThreadAndReply( - FROM_HERE, - base::Bind(&PerformanceMonitor::InitOnBackgroundThread, - base::Unretained(this)), - base::Bind(&PerformanceMonitor::FinishInit, - base::Unretained(this))); -} - -void PerformanceMonitor::InitOnBackgroundThread() { - CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); - - if (database_logging_enabled_) { - if (!database_) - database_ = Database::Create(database_path_); - - if (!database_) { - LOG(ERROR) << "Could not initialize database; aborting initialization."; - database_logging_enabled_ = false; - return; - } - - // Initialize the io thread's performance data to the value in the database; - // if there isn't a recording in the database, the value stays at 0. - Metric metric; - if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ, - &metric)) { - performance_data_for_io_thread_.network_bytes_read = metric.value; - } - } -} - -void PerformanceMonitor::FinishInit() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Events and notifications are only useful if we're logging to the database. - if (database_logging_enabled_) { - RegisterForNotifications(); - CheckForUncleanExits(); - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread, - base::Unretained(this))); - } - - // Post a task to the background thread to a function which does nothing. - // This will force any tasks the database is performing to finish prior to - // the reply being sent, since they use the same thread. - // - // Important! Make sure that methods in FinishInit() only rely on posting - // to the background thread, and do not rely upon a reply from the background - // thread; this is necessary for this notification to be valid. - util::PostTaskToDatabaseThreadAndReply( - FROM_HERE, - base::Bind(&base::DoNothing), - base::Bind(&PerformanceMonitor::NotifyInitialized, - base::Unretained(this))); -} - void PerformanceMonitor::StartGatherCycle() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Start our periodic gathering of metrics. - if (!disable_timer_autostart_for_testing_) - timer_.Reset(); -} - -void PerformanceMonitor::RegisterForNotifications() { - DCHECK(database_logging_enabled_); - - // Extensions - registrar_.Add( - this, - extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED, - content::NotificationService::AllSources()); - registrar_.Add(this, - extensions::NOTIFICATION_EXTENSION_ENABLED, - content::NotificationService::AllSources()); - registrar_.Add(this, - extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, - content::NotificationService::AllSources()); - registrar_.Add(this, - extensions::NOTIFICATION_CRX_INSTALLER_DONE, - content::NotificationService::AllSources()); - registrar_.Add(this, - extensions::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED, - content::NotificationService::AllSources()); - - // Crashes - registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, - content::NotificationService::AllSources()); - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, - content::NotificationService::AllSources()); - - // Profiles (for unclean exit) - registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED, - content::NotificationService::AllSources()); - - // Page load times - registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, - content::NotificationService::AllSources()); -} - -// We check if profiles exited cleanly initialization time in case they were -// loaded prior to PerformanceMonitor's initialization. Later profiles will be -// checked through the PROFILE_ADDED notification. -void PerformanceMonitor::CheckForUncleanExits() { - DCHECK(database_logging_enabled_); - - std::vector<Profile*> profiles = - g_browser_process->profile_manager()->GetLoadedProfiles(); - - for (std::vector<Profile*>::const_iterator iter = profiles.begin(); - iter != profiles.end(); ++iter) { - if ((*iter)->GetLastSessionExitType() == Profile::EXIT_CRASHED) { - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitor::AddUncleanExitEventOnBackgroundThread, - base::Unretained(this), - (*iter)->GetDebugName())); - } - } -} - -void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread( - const std::string& profile_name) { - DCHECK(database_logging_enabled_); - std::string database_key = kStateProfilePrefix + profile_name; - std::string last_active_string = database_->GetStateValue(database_key); - - // Check if there was no previous time; this should only happen if the profile - // was last used prior to PerformanceMonitor's integration. Do nothing in this - // case, since the event was prior to the beginning of our recording. - if (last_active_string.empty()) - return; - - base::Time last_active_time; - CHECK(StringToTime(last_active_string, &last_active_time)); - - scoped_ptr<Event> event = - util::CreateUncleanExitEvent(last_active_time, profile_name); - - database_->AddEvent(*event.get()); -} - -void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() { - CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(database_logging_enabled_); - - chrome::VersionInfo version; - DCHECK(version.is_valid()); - std::string current_version = version.Version(); - - std::string previous_version = database_->GetStateValue(kStateChromeVersion); - - // We should never have a current_version which is older than the - // previous_version. - DCHECK(current_version >= previous_version); - - // If this is the first run, there will not be a stored value for Chrome - // version; we insert the current version and will insert an event for the - // next update of Chrome. If the previous version is older than the current - // version, update the state in the database and insert an event. - if (current_version > previous_version) { - database_->AddStateValue(kStateChromeVersion, current_version); - if (!previous_version.empty()) { - scoped_ptr<Event> event = util::CreateChromeUpdateEvent( - base::Time::Now(), previous_version, current_version); - database_->AddEvent(*event.get()); - } - } -} - -void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) { - DCHECK(database_logging_enabled_); - - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitor::AddEventOnBackgroundThread, - base::Unretained(this), - base::Passed(&event))); -} - -void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) { - database_->AddEvent(*event.get()); -} - -void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) { - DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(database_logging_enabled_); - - database_->AddMetric(metric); -} - -void PerformanceMonitor::NotifyInitialized() { - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, - content::Source<PerformanceMonitor>(this), - content::NotificationService::NoDetails()); - - initialized_ = true; -} - -void PerformanceMonitor::DoTimedCollections() { -#if !defined(OS_ANDROID) - // The profile list is only useful for the logged events. - if (database_logging_enabled_) - UpdateLiveProfiles(); -#endif - - GatherMetricsMapOnUIThread(); + DCHECK_CURRENTLY_ON(BrowserThread::UI); + repeating_timer_.Start(FROM_HERE, + base::TimeDelta::FromSeconds(kGatherIntervalInSeconds), + this, + &PerformanceMonitor::GatherMetricsMapOnUIThread); } void PerformanceMonitor::GatherMetricsMapOnUIThread() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_CURRENTLY_ON(BrowserThread::UI); + static int current_update_sequence = 0; // Even in the "somewhat" unlikely event this wraps around, // it doesn't matter. We just check it for inequality. @@ -404,8 +69,8 @@ void PerformanceMonitor::GatherMetricsMapOnUIThread() { } void PerformanceMonitor::MarkProcessAsAlive(const base::ProcessHandle& handle, - int process_type, - int current_update_sequence) { + int process_type, + int current_update_sequence) { if (handle == 0) { // Process may not be valid yet. return; @@ -423,40 +88,9 @@ void PerformanceMonitor::MarkProcessAsAlive(const base::ProcessHandle& handle, } } -#if !defined(OS_ANDROID) -void PerformanceMonitor::UpdateLiveProfiles() { - std::string time = TimeToString(base::Time::Now()); - scoped_ptr<std::set<std::string> > active_profiles( - new std::set<std::string>()); - - for (chrome::BrowserIterator it; !it.done(); it.Next()) - active_profiles->insert(it->profile()->GetDebugName()); - - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper, - base::Unretained(this), - base::Passed(&active_profiles), - time)); -} - -void PerformanceMonitor::UpdateLiveProfilesHelper( - scoped_ptr<std::set<std::string> > active_profiles, - std::string time) { - CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(database_logging_enabled_); - - for (std::set<std::string>::const_iterator iter = active_profiles->begin(); - iter != active_profiles->end(); ++iter) { - database_->AddStateValue(kStateProfilePrefix + *iter, time); - } -} -#endif - void PerformanceMonitor::GatherMetricsMapOnIOThread( int current_update_sequence) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK_CURRENTLY_ON(BrowserThread::IO); // Find all child processes (does not include renderers), which has to be // done on the IO thread. @@ -471,29 +105,6 @@ void PerformanceMonitor::GatherMetricsMapOnIOThread( MarkProcessAsAlive(base::GetCurrentProcessHandle(), content::PROCESS_TYPE_BROWSER, current_update_sequence); - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitor::StoreMetricsOnBackgroundThread, - base::Unretained(this), current_update_sequence, - performance_data_for_io_thread_)); -} - -void PerformanceMonitor::StoreMetricsOnBackgroundThread( - int current_update_sequence, - const PerformanceDataForIOThread& performance_data_for_io_thread) { - CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); - - base::Time time_now = base::Time::Now(); - - // The timing can be off by kSampleIntervalInSeconds during any one particular - // run, but will be correct over time. - bool end_of_cycle = time_now >= next_collection_time_; - if (end_of_cycle) { - next_collection_time_ += - base::TimeDelta::FromSeconds(gather_interval_in_seconds_); - } - double cpu_usage = 0.0; size_t private_memory_sum = 0; size_t shared_memory_sum = 0; @@ -508,220 +119,20 @@ void PerformanceMonitor::StoreMetricsOnBackgroundThread( } else { process_metrics.SampleMetrics(); - if (end_of_cycle) { - // Gather averages of previously sampled metrics. - cpu_usage += process_metrics.GetAverageCPUUsage(); + // Gather averages of previously sampled metrics. + cpu_usage += process_metrics.GetAverageCPUUsage(); - size_t private_memory = 0; - size_t shared_memory = 0; - process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory); - private_memory_sum += private_memory; - shared_memory_sum += shared_memory; + size_t private_memory = 0; + size_t shared_memory = 0; + process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory); + private_memory_sum += private_memory; + shared_memory_sum += shared_memory; - process_metrics.EndOfCycle(); - } + process_metrics.EndOfCycle(); ++iter; } } - - // Store previously-sampled metrics. - if (end_of_cycle && database_logging_enabled_) { - if (!metrics_map_.empty()) { - database_->AddMetric(Metric(METRIC_CPU_USAGE, time_now, cpu_usage)); - database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE, - time_now, - static_cast<double>(private_memory_sum))); - database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE, - time_now, - static_cast<double>(shared_memory_sum))); - } - - database_->AddMetric( - Metric(METRIC_NETWORK_BYTES_READ, - time_now, - static_cast<double>( - performance_data_for_io_thread.network_bytes_read))); - } - - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&PerformanceMonitor::StartGatherCycle, - base::Unretained(this))); -} - -void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request, - const int bytes_read) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - if (initialized_ && !request.url().SchemeIsFile()) - performance_data_for_io_thread_.network_bytes_read += bytes_read; -} - -void PerformanceMonitor::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK(database_logging_enabled_); - - switch (type) { -#if defined(ENABLE_EXTENSIONS) - case extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED: { - AddExtensionEvent( - EVENT_EXTENSION_INSTALL, - content::Details<const extensions::InstalledExtensionInfo>(details)-> - extension); - break; - } - case extensions::NOTIFICATION_EXTENSION_ENABLED: { - AddExtensionEvent(EVENT_EXTENSION_ENABLE, - content::Details<Extension>(details).ptr()); - break; - } - case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { - const UnloadedExtensionInfo* info = - content::Details<UnloadedExtensionInfo>(details).ptr(); - - // Check if the extension was unloaded because it was disabled. - if (info->reason == UnloadedExtensionInfo::REASON_DISABLE) { - AddExtensionEvent(EVENT_EXTENSION_DISABLE, - info->extension); - } - break; - } - case extensions::NOTIFICATION_CRX_INSTALLER_DONE: { - const extensions::CrxInstaller* installer = - content::Source<extensions::CrxInstaller>(source).ptr(); - const extensions::Extension* extension = - content::Details<Extension>(details).ptr(); - - // Check if the reason for the install was due to a successful - // extension update. |extension| is NULL in case of install failure. - if (extension && - installer->install_cause() == extension_misc::INSTALL_CAUSE_UPDATE) { - AddExtensionEvent(EVENT_EXTENSION_UPDATE, extension); - } - break; - } - case extensions::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED: { - AddExtensionEvent(EVENT_EXTENSION_UNINSTALL, - content::Details<Extension>(details).ptr()); - break; - } -#endif // defined(ENABLE_EXTENSIONS) - case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: { - std::string url; - content::RenderWidgetHost* widget = - content::Source<content::RenderWidgetHost>(source).ptr(); - if (widget->IsRenderView()) { - content::RenderViewHost* view = content::RenderViewHost::From(widget); - MaybeGetURLFromRenderView(view, &url); - } - AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), - EVENT_RENDERER_HANG, - url)); - break; - } - case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { - AddRendererClosedEvent( - content::Source<content::RenderProcessHost>(source).ptr(), - *content::Details<content::RenderProcessHost::RendererClosedDetails>( - details).ptr()); - break; - } - case chrome::NOTIFICATION_PROFILE_ADDED: { - Profile* profile = content::Source<Profile>(source).ptr(); - if (profile->GetLastSessionExitType() == Profile::EXIT_CRASHED) { - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind( - &PerformanceMonitor::AddUncleanExitEventOnBackgroundThread, - base::Unretained(this), - profile->GetDebugName())); - } - break; - } - case content::NOTIFICATION_LOAD_STOP: { - const content::LoadNotificationDetails* load_details = - content::Details<content::LoadNotificationDetails>(details).ptr(); - if (!load_details) - break; - BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind( - &PerformanceMonitor::AddMetricOnBackgroundThread, - base::Unretained(this), - Metric(METRIC_PAGE_LOAD_TIME, - base::Time::Now(), - static_cast<double>( - load_details->load_time.ToInternalValue())))); - break; - } - default: { - NOTREACHED(); - break; - } - } -} - -#if defined(ENABLE_EXTENSIONS) -void PerformanceMonitor::AddExtensionEvent(EventType type, - const Extension* extension) { - DCHECK(type == EVENT_EXTENSION_INSTALL || - type == EVENT_EXTENSION_UNINSTALL || - type == EVENT_EXTENSION_UPDATE || - type == EVENT_EXTENSION_ENABLE || - type == EVENT_EXTENSION_DISABLE); - AddEvent(util::CreateExtensionEvent(type, - base::Time::Now(), - extension->id(), - extension->name(), - extension->url().spec(), - extension->location(), - extension->VersionString(), - extension->description())); -} -#endif // defined(ENABLE_EXTENSIONS) - -void PerformanceMonitor::AddRendererClosedEvent( - content::RenderProcessHost* host, - const content::RenderProcessHost::RendererClosedDetails& details) { - // We only care if this is an invalid termination. - if (details.status == base::TERMINATION_STATUS_NORMAL_TERMINATION || - details.status == base::TERMINATION_STATUS_STILL_RUNNING) - return; - - // Determine the type of crash. - EventType type = - details.status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ? - EVENT_RENDERER_KILLED : EVENT_RENDERER_CRASH; - - // A RenderProcessHost may contain multiple render views - for each valid - // render view, extract the url, and append it to the string, comma-separating - // the entries. - std::string url_list; - scoped_ptr<content::RenderWidgetHostIterator> widgets( - content::RenderWidgetHost::GetRenderWidgetHosts()); - while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { - if (widget->GetProcess()->GetID() != host->GetID()) - continue; - if (!widget->IsRenderView()) - continue; - - content::RenderViewHost* view = content::RenderViewHost::From(widget); - std::string url; - if (!MaybeGetURLFromRenderView(view, &url)) - continue; - - if (!url_list.empty()) - url_list += ", "; - - url_list += url; - } - - AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), type, url_list)); } } // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/performance_monitor.gyp b/chrome/browser/performance_monitor/performance_monitor.gyp deleted file mode 100644 index 4739109..0000000 --- a/chrome/browser/performance_monitor/performance_monitor.gyp +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'targets': [ - { - 'target_name': 'performance_monitor', - 'type': 'static_library', - 'sources': [ - '<@(schema_files)', - ], - 'includes': [ - '../../../build/json_schema_compile.gypi', - ], - 'variables': { - 'chromium_code': 1, - 'schema_files': [ - 'events.json', - ], - 'cc_dir': 'chrome/browser/performance_monitor', - 'root_namespace': 'performance_monitor::%(namespace)s', - }, - }, - ], -} diff --git a/chrome/browser/performance_monitor/performance_monitor.h b/chrome/browser/performance_monitor/performance_monitor.h index e016e81..afab37c 100644 --- a/chrome/browser/performance_monitor/performance_monitor.h +++ b/chrome/browser/performance_monitor/performance_monitor.h @@ -6,161 +6,39 @@ #define CHROME_BROWSER_PERFORMANCE_MONITOR_PERFORMANCE_MONITOR_H_ #include <map> -#include <set> -#include <string> -#include "base/files/file_path.h" -#include "base/memory/scoped_ptr.h" #include "base/process/process_handle.h" -#include "base/time/time.h" #include "base/timer/timer.h" -#include "chrome/browser/performance_monitor/event_type.h" #include "chrome/browser/performance_monitor/process_metrics_history.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/render_process_host.h" template <typename Type> struct DefaultSingletonTraits; -namespace extensions { -class Extension; -} - -namespace net { -class URLRequest; -} - namespace performance_monitor { -class Database; -class Event; -struct Metric; - -// PerformanceMonitor is a tool which will allow the user to view information -// about Chrome's performance over a period of time. It will gather statistics -// pertaining to performance-oriented areas (e.g. CPU usage, memory usage, and -// network usage) and will also store information about significant events which -// are related to performance, either being indicative (e.g. crashes) or -// potentially causal (e.g. extension installation/uninstallation). -// -// Thread Safety: PerformanceMonitor lives on multiple threads. When interacting -// with the Database, PerformanceMonitor acts on a background thread (which has -// the sequence guaranteed by a token, Database::kDatabaseSequenceToken). At -// other times, the PerformanceMonitor will act on the appropriate thread for -// the task (for instance, gathering statistics about CPU and memory usage -// is done on the background thread, but most notifications occur on the UI -// thread). -class PerformanceMonitor : public content::NotificationObserver { - public: - struct PerformanceDataForIOThread { - PerformanceDataForIOThread(); - - uint64 network_bytes_read; - }; +// PerformanceMonitor is a tool which periodically monitors performance metrics +// for histogram logging and possibly taking action upon noticing serious +// performance degradation. +class PerformanceMonitor { + public: typedef std::map<base::ProcessHandle, ProcessMetricsHistory> MetricsMap; - // Set the path which the PerformanceMonitor should use for the database files - // constructed. This must be done prior to the initialization of the - // PerformanceMonitor. Returns true on success, false on failure (failure - // likely indicates that PerformanceMonitor has already been started at the - // time of the call). - bool SetDatabasePath(const base::FilePath& path); - - bool database_logging_enabled() const { return database_logging_enabled_; } - // Returns the current PerformanceMonitor instance if one exists; otherwise // constructs a new PerformanceMonitor. static PerformanceMonitor* GetInstance(); - // Begins the initialization process for the PerformanceMonitor in order to - // start collecting data. - void Initialize(); - // Start the cycle of metrics gathering. void StartGatherCycle(); - // Inform PerformanceMonitor that bytes have been read; if these came across - // the network (and PerformanceMonitor is initialized), then increment the - // count accordingly. - void BytesReadOnIOThread(const net::URLRequest& request, const int bytes); - - // content::NotificationObserver - // Wait for various notifications; insert events into the database upon - // occurance. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - Database* database() { return database_.get(); } - base::FilePath database_path() { return database_path_; } - static bool initialized() { return initialized_; } - private: friend struct DefaultSingletonTraits<PerformanceMonitor>; - friend class PerformanceMonitorBrowserTest; - FRIEND_TEST_ALL_PREFIXES(PerformanceMonitorUncleanExitBrowserTest, - OneProfileUncleanExit); - FRIEND_TEST_ALL_PREFIXES(PerformanceMonitorUncleanExitBrowserTest, - TwoProfileUncleanExit); - FRIEND_TEST_ALL_PREFIXES(PerformanceMonitorBrowserTest, NetworkBytesRead); PerformanceMonitor(); virtual ~PerformanceMonitor(); - // Perform any additional initialization which must be performed on a - // background thread (e.g. constructing the database). - void InitOnBackgroundThread(); - - void FinishInit(); - - // Create the persistent database if we haven't already done so. - void InitializeDatabaseIfNeeded(); - - // Register for the appropriate notifications as a NotificationObserver. - void RegisterForNotifications(); - - // Checks for whether the previous profiles closed uncleanly; this method - // should only be called once per run in order to avoid duplication of events - // (exceptions made for testing purposes where we construct the environment). - void CheckForUncleanExits(); - - // Find the last active time for the profile and insert the event into the - // database. - void AddUncleanExitEventOnBackgroundThread(const std::string& profile_name); - - // Check the previous Chrome version from the Database and determine if - // it has been updated. If it has, insert an event in the database. - void CheckForVersionUpdateOnBackgroundThread(); - - // Wrapper function for inserting events into the database. - void AddEvent(scoped_ptr<Event> event); - - void AddEventOnBackgroundThread(scoped_ptr<Event> event); - - // Since Database::AddMetric() is overloaded, base::Bind() does not work and - // we need a helper function. - void AddMetricOnBackgroundThread(const Metric& metric); - - // Notify any listeners that PerformanceMonitor has finished the initializing. - void NotifyInitialized(); - // Perform any collections that are done on a timed basis. void DoTimedCollections(); - // Update the database record of the last time the active profiles were - // running; this is used in determining when an unclean exit occurred. -#if !defined(OS_ANDROID) - void UpdateLiveProfiles(); - void UpdateLiveProfilesHelper( - scoped_ptr<std::set<std::string> > active_profiles, std::string time); -#endif - - // Stores CPU/memory usage metrics to the database. - void StoreMetricsOnBackgroundThread( - int current_update_sequence, - const PerformanceDataForIOThread& performance_data_for_io_thread); - // Mark the given process as alive in the current update iteration. // This means adding an entry to the map of watched processes if it's not // already present. @@ -173,55 +51,11 @@ class PerformanceMonitor : public content::NotificationObserver { void GatherMetricsMapOnUIThread(); void GatherMetricsMapOnIOThread(int current_update_sequence); -#if defined(ENABLE_EXTENSIONS) - // Generate an appropriate ExtensionEvent for an extension-related occurrance - // and insert it in the database. - void AddExtensionEvent(EventType type, - const extensions::Extension* extension); -#endif - - // Generate an appropriate RendererFailure for a renderer crash and insert it - // in the database. - void AddRendererClosedEvent( - content::RenderProcessHost* host, - const content::RenderProcessHost::RendererClosedDetails& details); - - // The store for all performance data that must be gathered from the IO - // thread. - PerformanceDataForIOThread performance_data_for_io_thread_; - - // The location at which the database files are stored; if empty, the database - // will default to '<user_data_dir>/performance_monitor_dbs'. - base::FilePath database_path_; - - scoped_ptr<Database> database_; - // A map of currently running ProcessHandles to ProcessMetrics. MetricsMap metrics_map_; - // The next time we should collect averages from the performance metrics - // and act on them. - base::Time next_collection_time_; - - // How long to wait between collections. - int gather_interval_in_seconds_; - - // Enable persistent logging of performance metrics to a database. - bool database_logging_enabled_; - // The timer to signal PerformanceMonitor to perform its timed collections. - base::DelayTimer<PerformanceMonitor> timer_; - - content::NotificationRegistrar registrar_; - - // A flag indicating whether or not PerformanceMonitor is initialized. Any - // external sources accessing PerformanceMonitor should either wait for - // the PERFORMANCE_MONITOR_INITIALIZED notification or should check this - // flag. - static bool initialized_; - - // Disable auto-starting the collection timer; used for tests. - bool disable_timer_autostart_for_testing_; + base::RepeatingTimer<PerformanceMonitor> repeating_timer_; DISALLOW_COPY_AND_ASSIGN(PerformanceMonitor); }; diff --git a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc deleted file mode 100644 index 81519c9f..0000000 --- a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc +++ /dev/null @@ -1,842 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/strings/string_number_conversions.h" -#include "base/threading/sequenced_worker_pool.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/performance_monitor/constants.h" -#include "chrome/browser/performance_monitor/database.h" -#include "chrome/browser/performance_monitor/metric.h" -#include "chrome/browser/performance_monitor/performance_monitor.h" -#include "chrome/browser/prefs/session_startup_pref.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/sessions/session_service.h" -#include "chrome/browser/sessions/session_service_factory.h" -#include "chrome/browser/sessions/session_service_test_helper.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_commands.h" -#include "chrome/browser/ui/browser_navigator.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/host_desktop.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/chrome_version_info.h" -#include "chrome/common/url_constants.h" -#include "chrome/test/base/ui_test_utils.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_service.h" -#include "content/public/common/page_transition_types.h" -#include "content/public/test/browser_test_utils.h" -#include "content/public/test/test_navigation_observer.h" -#include "content/public/test/test_utils.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_system.h" -#include "extensions/common/extension.h" - -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/profiles/profile_helper.h" -#include "chromeos/chromeos_switches.h" -#include "components/user_manager/user_manager.h" -#endif - -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -using extensions::Extension; - -namespace performance_monitor { - -namespace { - -const base::TimeDelta kMaxStartupTime = base::TimeDelta::FromMinutes(3); - -#if defined(OS_CHROMEOS) -// User account email and directory hash for secondary account for multi-profile -// sensitive test cases. -const char kSecondProfileAccount[] = "profile2@test.com"; -const char kSecondProfileHash[] = "profile2"; -#endif - -// Helper struct to store the information of an extension; this is needed if the -// pointer to the extension ever becomes invalid (e.g., if we uninstall the -// extension). -struct ExtensionBasicInfo { - // Empty constructor for stl-container-happiness. - ExtensionBasicInfo() { - } - explicit ExtensionBasicInfo(const Extension* extension) - : description(extension->description()), - id(extension->id()), - name(extension->name()), - url(extension->url().spec()), - version(extension->VersionString()), - location(extension->location()) { - } - - std::string description; - std::string id; - std::string name; - std::string url; - std::string version; - extensions::Manifest::Location location; -}; - -// Compare the fields of |extension| to those in |value|; this is a check to -// make sure the extension data was recorded properly in the event. -void ValidateExtensionInfo(const ExtensionBasicInfo extension, - const base::DictionaryValue* value) { - std::string extension_description; - std::string extension_id; - std::string extension_name; - std::string extension_url; - std::string extension_version; - int extension_location; - - ASSERT_TRUE(value->GetString("extensionDescription", - &extension_description)); - ASSERT_EQ(extension.description, extension_description); - ASSERT_TRUE(value->GetString("extensionId", &extension_id)); - ASSERT_EQ(extension.id, extension_id); - ASSERT_TRUE(value->GetString("extensionName", &extension_name)); - ASSERT_EQ(extension.name, extension_name); - ASSERT_TRUE(value->GetString("extensionUrl", &extension_url)); - ASSERT_EQ(extension.url, extension_url); - ASSERT_TRUE(value->GetString("extensionVersion", &extension_version)); - ASSERT_EQ(extension.version, extension_version); - ASSERT_TRUE(value->GetInteger("extensionLocation", &extension_location)); - ASSERT_EQ(extension.location, extension_location); -} - -// Verify that a particular event has the proper type. -void CheckEventType(int expected_event_type, const linked_ptr<Event>& event) { - int event_type = -1; - ASSERT_TRUE(event->data()->GetInteger("eventType", &event_type)); - ASSERT_EQ(expected_event_type, event_type); - ASSERT_EQ(expected_event_type, event->type()); -} - -// Verify that we received the proper number of events, checking the type of -// each one. -void CheckEventTypes(const std::vector<int>& expected_event_types, - const Database::EventVector& events) { - ASSERT_EQ(expected_event_types.size(), events.size()); - - for (size_t i = 0; i < expected_event_types.size(); ++i) - CheckEventType(expected_event_types[i], events[i]); -} - -// Check that we received the proper number of events, that each event is of the -// proper type, and that each event recorded the proper information about the -// extension. -void CheckExtensionEvents( - const std::vector<int>& expected_event_types, - const Database::EventVector& events, - const std::vector<ExtensionBasicInfo>& extension_infos) { - CheckEventTypes(expected_event_types, events); - - for (size_t i = 0; i < expected_event_types.size(); ++i) { - ValidateExtensionInfo(extension_infos[i], events[i]->data()); - int event_type; - ASSERT_TRUE(events[i]->data()->GetInteger("eventType", &event_type)); - ASSERT_EQ(expected_event_types[i], event_type); - } -} - -} // namespace - -class PerformanceMonitorBrowserTest : public ExtensionBrowserTest { - public: - virtual void SetUpOnMainThread() OVERRIDE { - CHECK(db_dir_.CreateUniqueTempDir()); - performance_monitor_ = PerformanceMonitor::GetInstance(); - performance_monitor_->SetDatabasePath(db_dir_.path()); - - // PerformanceMonitor's initialization process involves a significant - // amount of thread-hopping between the UI thread and the background thread. - // If we begin the tests prior to full initialization, we cannot predict - // the behavior or mock synchronicity as we must. Wait for initialization - // to complete fully before proceeding with the test. - content::WindowedNotificationObserver windowed_observer( - chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, - content::NotificationService::AllSources()); - - // We stop the timer in charge of doing timed collections so that we can - // enforce when, and how many times, we do these collections. - performance_monitor_->disable_timer_autostart_for_testing_ = true; - // Force metrics to be stored, regardless of switches used. - performance_monitor_->database_logging_enabled_ = true; - performance_monitor_->Initialize(); - - windowed_observer.Wait(); - } - - // A handle for gathering statistics from the database, which must be done on - // the background thread. Since we are testing, we can mock synchronicity with - // FlushForTesting(). - void GatherStatistics() { - performance_monitor_->next_collection_time_ = base::Time::Now(); - performance_monitor_->GatherMetricsMapOnUIThread(); - - RunAllPendingInMessageLoop(content::BrowserThread::IO); - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - } - - void GetEventsOnBackgroundThread(Database::EventVector* events) { - // base::Time is potentially flaky in that there is no guarantee that it - // won't actually decrease between successive calls. If we call GetEvents - // and the Database uses base::Time::Now() and gets a lesser time, then it - // will return 0 events. Thus, we use a time that is guaranteed to be in the - // future (for at least the next couple hundred thousand years). - *events = performance_monitor_->database()->GetEvents( - base::Time(), base::Time::FromInternalValue(kint64max)); - } - - // A handle for getting the events from the database, which must be done on - // the background thread. Since we are testing, we can mock synchronicity - // with FlushForTesting(). - Database::EventVector GetEvents() { - // Ensure that any event insertions happen prior to getting events in order - // to avoid race conditions. - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - content::RunAllPendingInMessageLoop(); - - Database::EventVector events; - content::BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitorBrowserTest::GetEventsOnBackgroundThread, - base::Unretained(this), - &events)); - - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - return events; - } - - void GetStatsOnBackgroundThread(Database::MetricVector* metrics, - MetricType type) { - *metrics = *performance_monitor_->database()->GetStatsForActivityAndMetric( - type, base::Time(), base::Time::FromInternalValue(kint64max)); - } - - // A handle for getting statistics from the database (see previous comments on - // GetEvents() and GetEventsOnBackgroundThread). - Database::MetricVector GetStats(MetricType type) { - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - content::RunAllPendingInMessageLoop(); - - Database::MetricVector metrics; - content::BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitorBrowserTest::GetStatsOnBackgroundThread, - base::Unretained(this), - &metrics, - type)); - - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - return metrics; - } - - // A handle for inserting a state value into the database, which must be done - // on the background thread. This is useful for mocking up a scenario in which - // the database has prior data stored. We mock synchronicity with - // FlushForTesting(). - void AddStateValue(const std::string& key, const std::string& value) { - content::BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(base::IgnoreResult(&Database::AddStateValue), - base::Unretained(performance_monitor()->database()), - key, - value)); - - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - } - - // A handle for PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread(); - // we mock synchronicity with FlushForTesting(). - void CheckForVersionUpdate() { - content::BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread, - base::Unretained(performance_monitor()))); - - content::BrowserThread::GetBlockingPool()->FlushForTesting(); - } - - PerformanceMonitor* performance_monitor() const { - return performance_monitor_; - } - - protected: - base::ScopedTempDir db_dir_; - PerformanceMonitor* performance_monitor_; -}; - -class PerformanceMonitorUncleanExitBrowserTest - : public PerformanceMonitorBrowserTest, - public testing::WithParamInterface<bool> { - public: - virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { - PerformanceMonitorBrowserTest::SetUpCommandLine(command_line); -#if defined(OS_CHROMEOS) - command_line->AppendSwitch( - chromeos::switches::kIgnoreUserProfileMappingForTests); -#endif - } - - virtual bool SetUpUserDataDirectory() OVERRIDE { - base::FilePath user_data_directory; - PathService::Get(chrome::DIR_USER_DATA, &user_data_directory); - - // On CrOS, if we are "logged in" with the --login-profile switch, - // the default profile will be different. We check if we are logged in, and, - // if we are, we use that profile name instead. (Note: trybots will - // typically be logged in with 'user'.) -#if defined(OS_CHROMEOS) - const CommandLine command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(chromeos::switches::kLoginProfile)) { - first_profile_name_ = - command_line.GetSwitchValueASCII(chromeos::switches::kLoginProfile); - } else { - first_profile_name_ = chrome::kInitialProfile; - } -#else - first_profile_name_ = chrome::kInitialProfile; -#endif - - base::FilePath first_profile = - user_data_directory.AppendASCII(first_profile_name_); - CHECK(base::CreateDirectory(first_profile)); - - base::FilePath stock_prefs_file; - PathService::Get(chrome::DIR_TEST_DATA, &stock_prefs_file); - stock_prefs_file = stock_prefs_file.AppendASCII("performance_monitor") - .AppendASCII("unclean_exit_prefs"); - CHECK(base::PathExists(stock_prefs_file)); - - base::FilePath first_profile_prefs_file = - first_profile.Append(chrome::kPreferencesFilename); - CHECK(base::CopyFile(stock_prefs_file, first_profile_prefs_file)); - CHECK(base::PathExists(first_profile_prefs_file)); - - second_profile_name_ = - std::string(chrome::kMultiProfileDirPrefix) - .append(base::IntToString(1)); -#if defined(OS_CHROMEOS) - if (GetParam()) { - second_profile_name_ = chromeos::ProfileHelper::GetUserProfileDir( - kSecondProfileHash).BaseName().value(); - } -#endif - - base::FilePath second_profile = - user_data_directory.AppendASCII(second_profile_name_); - CHECK(base::CreateDirectory(second_profile)); - - base::FilePath second_profile_prefs_file = - second_profile.Append(chrome::kPreferencesFilename); - CHECK(base::CopyFile(stock_prefs_file, second_profile_prefs_file)); - CHECK(base::PathExists(second_profile_prefs_file)); - - return true; - } - -#if defined(OS_CHROMEOS) - virtual void AddSecondUserAccount() { - // Add second user account for multi-profile test. - if (GetParam()) { - user_manager::UserManager::Get()->UserLoggedIn( - kSecondProfileAccount, kSecondProfileHash, false); - } - } -#endif - - protected: - std::string first_profile_name_; - std::string second_profile_name_; -}; - -class PerformanceMonitorSessionRestoreBrowserTest - : public PerformanceMonitorBrowserTest { - public: - virtual void SetUpOnMainThread() OVERRIDE { - SessionStartupPref pref(SessionStartupPref::LAST); - SessionStartupPref::SetStartupPref(browser()->profile(), pref); -#if defined(OS_CHROMEOS) || defined (OS_MACOSX) - // Undo the effect of kBrowserAliveWithNoWindows in defaults.cc so that we - // can get these test to work without quitting. - SessionServiceTestHelper helper( - SessionServiceFactory::GetForProfile(browser()->profile())); - helper.SetForceBrowserNotAliveWithNoWindows(true); - helper.ReleaseService(); -#endif - - PerformanceMonitorBrowserTest::SetUpOnMainThread(); - } - - Browser* QuitBrowserAndRestore(Browser* browser, int expected_tab_count) { - Profile* profile = browser->profile(); - - // Close the browser. - g_browser_process->AddRefModule(); - content::WindowedNotificationObserver observer( - chrome::NOTIFICATION_BROWSER_CLOSED, - content::NotificationService::AllSources()); - browser->window()->Close(); -#if defined(OS_MACOSX) - // BrowserWindowController depends on the auto release pool being recycled - // in the message loop to delete itself, which frees the Browser object - // which fires this event. - AutoreleasePool()->Recycle(); -#endif - observer.Wait(); - - // Create a new window, which should trigger session restore. - content::TestNavigationObserver restore_observer(NULL, expected_tab_count); - restore_observer.StartWatchingNewWebContents(); - ui_test_utils::BrowserAddedObserver window_observer; - chrome::NewEmptyWindow(profile, chrome::GetActiveDesktop()); - Browser* new_browser = window_observer.WaitForSingleNewBrowser(); - restore_observer.Wait(); - g_browser_process->ReleaseModule(); - - return new_browser; - } -}; - -// Test that PerformanceMonitor will correctly record an extension installation -// event. -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, InstallExtensionEvent) { - base::FilePath extension_path; - PathService::Get(chrome::DIR_TEST_DATA, &extension_path); - extension_path = extension_path.AppendASCII("performance_monitor") - .AppendASCII("extensions") - .AppendASCII("simple_extension_v1"); - const Extension* extension = LoadExtension(extension_path); - - std::vector<ExtensionBasicInfo> extension_infos; - extension_infos.push_back(ExtensionBasicInfo(extension)); - - std::vector<int> expected_event_types; - expected_event_types.push_back(EVENT_EXTENSION_INSTALL); - - Database::EventVector events = GetEvents(); - CheckExtensionEvents(expected_event_types, events, extension_infos); -} - -// Test that PerformanceMonitor will correctly record events as an extension is -// disabled and enabled. -// Test is falky, see http://crbug.com/157980 -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, - DISABLED_DisableAndEnableExtensionEvent) { - const int kNumEvents = 3; - - base::FilePath extension_path; - PathService::Get(chrome::DIR_TEST_DATA, &extension_path); - extension_path = extension_path.AppendASCII("performance_monitor") - .AppendASCII("extensions") - .AppendASCII("simple_extension_v1"); - const Extension* extension = LoadExtension(extension_path); - - DisableExtension(extension->id()); - EnableExtension(extension->id()); - - std::vector<ExtensionBasicInfo> extension_infos; - // There will be three events in all, each pertaining to the same extension: - // Extension Install - // Extension Disable - // Extension Enable - for (int i = 0; i < kNumEvents; ++i) - extension_infos.push_back(ExtensionBasicInfo(extension)); - - std::vector<int> expected_event_types; - expected_event_types.push_back(EVENT_EXTENSION_INSTALL); - expected_event_types.push_back(EVENT_EXTENSION_DISABLE); - expected_event_types.push_back(EVENT_EXTENSION_ENABLE); - - Database::EventVector events = GetEvents(); - CheckExtensionEvents(expected_event_types, events, extension_infos); -} - -// Test that PerformanceMonitor correctly records an extension update event. -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, UpdateExtensionEvent) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - base::FilePath test_data_dir; - PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); - test_data_dir = test_data_dir.AppendASCII("performance_monitor") - .AppendASCII("extensions"); - - // We need two versions of the same extension. - base::FilePath pem_path = test_data_dir.AppendASCII("simple_extension.pem"); - base::FilePath path_v1_ = PackExtensionWithOptions( - test_data_dir.AppendASCII("simple_extension_v1"), - temp_dir.path().AppendASCII("simple_extension1.crx"), - pem_path, - base::FilePath()); - base::FilePath path_v2_ = PackExtensionWithOptions( - test_data_dir.AppendASCII("simple_extension_v2"), - temp_dir.path().AppendASCII("simple_extension2.crx"), - pem_path, - base::FilePath()); - - const extensions::Extension* extension = InstallExtension(path_v1_, 1); - - std::vector<ExtensionBasicInfo> extension_infos; - extension_infos.push_back(ExtensionBasicInfo(extension)); - - ExtensionService* extension_service = extensions::ExtensionSystem::Get( - browser()->profile())->extension_service(); - - extensions::CrxInstaller* crx_installer = NULL; - - // Create an observer to wait for the update to finish. - content::WindowedNotificationObserver windowed_observer( - extensions::NOTIFICATION_CRX_INSTALLER_DONE, - content::Source<extensions::CrxInstaller>(crx_installer)); - ASSERT_TRUE(extension_service->UpdateExtension( - extension->id(), path_v2_, true, &crx_installer)); - windowed_observer.Wait(); - - extension = extensions::ExtensionRegistry::Get( - browser()->profile())->enabled_extensions().GetByID( - extension_infos[0].id); - - // The total series of events for this process will be: - // Extension Install - install version 1 - // Extension Install - install version 2 - // Extension Update - signal the udate to version 2 - // We push back the corresponding ExtensionBasicInfos. - extension_infos.push_back(ExtensionBasicInfo(extension)); - extension_infos.push_back(extension_infos[1]); - - std::vector<int> expected_event_types; - expected_event_types.push_back(EVENT_EXTENSION_INSTALL); - expected_event_types.push_back(EVENT_EXTENSION_INSTALL); - expected_event_types.push_back(EVENT_EXTENSION_UPDATE); - - Database::EventVector events = GetEvents(); - - CheckExtensionEvents(expected_event_types, events, extension_infos); -} - -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, UninstallExtensionEvent) { - const int kNumEvents = 2; - base::FilePath extension_path; - PathService::Get(chrome::DIR_TEST_DATA, &extension_path); - extension_path = extension_path.AppendASCII("performance_monitor") - .AppendASCII("extensions") - .AppendASCII("simple_extension_v1"); - const Extension* extension = LoadExtension(extension_path); - - std::vector<ExtensionBasicInfo> extension_infos; - // There will be two events, both pertaining to the same extension: - // Extension Install - // Extension Uninstall - for (int i = 0; i < kNumEvents; ++i) - extension_infos.push_back(ExtensionBasicInfo(extension)); - - UninstallExtension(extension->id()); - - std::vector<int> expected_event_types; - expected_event_types.push_back(EVENT_EXTENSION_INSTALL); - expected_event_types.push_back(EVENT_EXTENSION_UNINSTALL); - - Database::EventVector events = GetEvents(); - - CheckExtensionEvents(expected_event_types, events, extension_infos); -} - -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, NewVersionEvent) { - const char kOldVersion[] = "0.0"; - - // The version in the database right now will be the current version of chrome - // (gathered at initialization of PerformanceMonitor). Replace this with an - // older version so an event is generated. - AddStateValue(kStateChromeVersion, kOldVersion); - - CheckForVersionUpdate(); - - chrome::VersionInfo version; - ASSERT_TRUE(version.is_valid()); - std::string version_string = version.Version(); - - Database::EventVector events = GetEvents(); - ASSERT_EQ(1u, events.size()); - ASSERT_EQ(EVENT_CHROME_UPDATE, events[0]->type()); - - const base::DictionaryValue* value; - ASSERT_TRUE(events[0]->data()->GetAsDictionary(&value)); - - std::string previous_version; - std::string current_version; - - ASSERT_TRUE(value->GetString("previousVersion", &previous_version)); - ASSERT_EQ(kOldVersion, previous_version); - ASSERT_TRUE(value->GetString("currentVersion", ¤t_version)); - ASSERT_EQ(version_string, current_version); -} - -// crbug.com/160502 -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, - DISABLED_GatherStatistics) { - GatherStatistics(); - - // No stats should be recorded for this CPUUsage because this was the first - // call to GatherStatistics. - Database::MetricVector stats = GetStats(METRIC_CPU_USAGE); - ASSERT_EQ(0u, stats.size()); - - stats = GetStats(METRIC_PRIVATE_MEMORY_USAGE); - ASSERT_EQ(1u, stats.size()); - EXPECT_GT(stats[0].value, 0); - - stats = GetStats(METRIC_SHARED_MEMORY_USAGE); - ASSERT_EQ(1u, stats.size()); - EXPECT_GT(stats[0].value, 0); - - // Open new tabs to incur CPU usage. - for (int i = 0; i < 10; ++i) { - chrome::NavigateParams params( - browser(), ui_test_utils::GetTestUrl( - base::FilePath(base::FilePath::kCurrentDirectory), - base::FilePath(FILE_PATH_LITERAL("title1.html"))), - content::PAGE_TRANSITION_LINK); - params.disposition = NEW_BACKGROUND_TAB; - ui_test_utils::NavigateToURL(¶ms); - } - GatherStatistics(); - - // One CPUUsage stat should exist now. - stats = GetStats(METRIC_CPU_USAGE); - ASSERT_EQ(1u, stats.size()); - EXPECT_GT(stats[0].value, 0); - - stats = GetStats(METRIC_PRIVATE_MEMORY_USAGE); - ASSERT_EQ(2u, stats.size()); - EXPECT_GT(stats[1].value, 0); - - stats = GetStats(METRIC_SHARED_MEMORY_USAGE); - ASSERT_EQ(2u, stats.size()); - EXPECT_GT(stats[1].value, 0); -} - -// Disabled on other platforms because of flakiness: http://crbug.com/159172. -#if !defined(OS_WIN) -// Disabled on Windows due to a bug where Windows will return a normal exit -// code in the testing environment, even if the process died (this is not the -// case when hand-testing). This code can be traced to MSDN functions in -// base::GetTerminationStatus(), so there's not much we can do. -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, - DISABLED_RendererKilledEvent) { - content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents()); - - Database::EventVector events = GetEvents(); - - ASSERT_EQ(1u, events.size()); - CheckEventType(EVENT_RENDERER_KILLED, events[0]); - - // Check the url - since we never went anywhere, this should be about:blank. - std::string url; - ASSERT_TRUE(events[0]->data()->GetString("url", &url)); - ASSERT_EQ("about:blank", url); -} -#endif // !defined(OS_WIN) - -// TODO(jam): http://crbug.com/350550 -#if !(defined(OS_CHROMEOS) && defined(ADDRESS_SANITIZER)) -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, RendererCrashEvent) { - content::RenderProcessHostWatcher observer( - browser()->tab_strip_model()->GetActiveWebContents(), - content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); - - ui_test_utils::NavigateToURL(browser(), GURL(content::kChromeUICrashURL)); - - observer.Wait(); - - Database::EventVector events = GetEvents(); - ASSERT_EQ(1u, events.size()); - - CheckEventType(EVENT_RENDERER_CRASH, events[0]); - - std::string url; - ASSERT_TRUE(events[0]->data()->GetString("url", &url)); - ASSERT_EQ("chrome://crash/", url); -} -#endif - -IN_PROC_BROWSER_TEST_P(PerformanceMonitorUncleanExitBrowserTest, - OneProfileUncleanExit) { - // Initialize the database value (if there's no value in the database, it - // can't determine the last active time of the profile, and doesn't insert - // the event). - const std::string time = "12985807272597591"; - AddStateValue(kStateProfilePrefix + first_profile_name_, time); - - performance_monitor()->CheckForUncleanExits(); - content::RunAllPendingInMessageLoop(); - - Database::EventVector events = GetEvents(); - - const size_t kNumEvents = 1; - ASSERT_EQ(kNumEvents, events.size()); - - CheckEventType(EVENT_UNCLEAN_EXIT, events[0]); - - std::string event_profile; - ASSERT_TRUE(events[0]->data()->GetString("profileName", &event_profile)); - ASSERT_EQ(first_profile_name_, event_profile); -} - -IN_PROC_BROWSER_TEST_P(PerformanceMonitorUncleanExitBrowserTest, - TwoProfileUncleanExit) { -#if defined(OS_CHROMEOS) - AddSecondUserAccount(); -#endif - - base::FilePath second_profile_path; - PathService::Get(chrome::DIR_USER_DATA, &second_profile_path); - second_profile_path = second_profile_path.AppendASCII(second_profile_name_); - - const std::string time1 = "12985807272597591"; - const std::string time2 = "12985807272599918"; - - // Initialize the database. - AddStateValue(kStateProfilePrefix + first_profile_name_, time1); - AddStateValue(kStateProfilePrefix + second_profile_name_, time2); - - performance_monitor()->CheckForUncleanExits(); - content::RunAllPendingInMessageLoop(); - - // Load the second profile, which has also exited uncleanly. Note that since - // the second profile is new, component extensions will be installed as part - // of the browser startup for that profile, generating extra events. - g_browser_process->profile_manager()->GetProfile(second_profile_path); - content::RunAllPendingInMessageLoop(); - - Database::EventVector events = GetEvents(); - - const size_t kNumUncleanExitEvents = 2; - size_t num_unclean_exit_events = 0; - for (size_t i = 0; i < events.size(); ++i) { - int event_type = -1; - if (events[i]->data()->GetInteger("eventType", &event_type) && - event_type == EVENT_EXTENSION_INSTALL) { - continue; - } - CheckEventType(EVENT_UNCLEAN_EXIT, events[i]); - ++num_unclean_exit_events; - } - ASSERT_EQ(kNumUncleanExitEvents, num_unclean_exit_events); - - std::string event_profile; - ASSERT_TRUE(events[0]->data()->GetString("profileName", &event_profile)); - ASSERT_EQ(first_profile_name_, event_profile); - - ASSERT_TRUE(events[1]->data()->GetString("profileName", &event_profile)); - ASSERT_EQ(second_profile_name_, event_profile); -} - -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, StartupTime) { - Database::MetricVector metrics = GetStats(METRIC_TEST_STARTUP_TIME); - - ASSERT_EQ(1u, metrics.size()); - ASSERT_LT(metrics[0].value, kMaxStartupTime.ToInternalValue()); -} - -IN_PROC_BROWSER_TEST_F(PerformanceMonitorSessionRestoreBrowserTest, - StartupWithSessionRestore) { - ui_test_utils::NavigateToURL( - browser(), ui_test_utils::GetTestUrl( - base::FilePath(base::FilePath::kCurrentDirectory), - base::FilePath(FILE_PATH_LITERAL("title1.html")))); - - QuitBrowserAndRestore(browser(), 1); - - Database::MetricVector metrics = GetStats(METRIC_TEST_STARTUP_TIME); - ASSERT_EQ(1u, metrics.size()); - ASSERT_LT(metrics[0].value, kMaxStartupTime.ToInternalValue()); - - metrics = GetStats(METRIC_SESSION_RESTORE_TIME); - ASSERT_EQ(1u, metrics.size()); - ASSERT_LT(metrics[0].value, kMaxStartupTime.ToInternalValue()); -} - -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, PageLoadTime) { - const base::TimeDelta kMaxLoadTime = base::TimeDelta::FromSeconds(30); - - ui_test_utils::NavigateToURL( - browser(), ui_test_utils::GetTestUrl( - base::FilePath(base::FilePath::kCurrentDirectory), - base::FilePath(FILE_PATH_LITERAL("title1.html")))); - - ui_test_utils::NavigateToURL( - browser(), ui_test_utils::GetTestUrl( - base::FilePath(base::FilePath::kCurrentDirectory), - base::FilePath(FILE_PATH_LITERAL("title1.html")))); - - Database::MetricVector metrics = GetStats(METRIC_PAGE_LOAD_TIME); - - ASSERT_EQ(2u, metrics.size()); - ASSERT_LT(metrics[0].value, kMaxLoadTime.ToInternalValue()); - ASSERT_LT(metrics[1].value, kMaxLoadTime.ToInternalValue()); -} - -IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, NetworkBytesRead) { - base::FilePath test_dir; - PathService::Get(chrome::DIR_TEST_DATA, &test_dir); - - int64 page1_size = 0; - ASSERT_TRUE(base::GetFileSize(test_dir.AppendASCII("title1.html"), - &page1_size)); - - int64 page2_size = 0; - ASSERT_TRUE(base::GetFileSize(test_dir.AppendASCII("title2.html"), - &page2_size)); - - ASSERT_TRUE(test_server()->Start()); - - ui_test_utils::NavigateToURL( - browser(), - test_server()->GetURL(std::string("files/").append("title1.html"))); - - GatherStatistics(); - - Database::MetricVector metrics = GetStats(METRIC_NETWORK_BYTES_READ); - ASSERT_EQ(1u, metrics.size()); - // Since these pages are read over the "network" (actually the test_server), - // some extraneous information is carried along, and the best check we can do - // is for greater than or equal to. - EXPECT_GE(metrics[0].value, page1_size); - - ui_test_utils::NavigateToURL( - browser(), - test_server()->GetURL(std::string("files/").append("title2.html"))); - - GatherStatistics(); - - metrics = GetStats(METRIC_NETWORK_BYTES_READ); - ASSERT_EQ(2u, metrics.size()); - EXPECT_GE(metrics[1].value, page1_size + page2_size); -} - -INSTANTIATE_TEST_CASE_P(PerformanceMonitorUncleanExitBrowserTestInstantiation, - PerformanceMonitorUncleanExitBrowserTest, - testing::Bool()); - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/performance_monitor_util.cc b/chrome/browser/performance_monitor/performance_monitor_util.cc deleted file mode 100644 index 7f94a01..0000000 --- a/chrome/browser/performance_monitor/performance_monitor_util.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/performance_monitor_util.h" - -#include "base/json/json_writer.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_number_conversions.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/time/time.h" -#include "chrome/browser/performance_monitor/events.h" -#include "content/public/browser/browser_thread.h" - -namespace performance_monitor { -namespace util { - -bool PostTaskToDatabaseThreadAndReply( - const tracked_objects::Location& from_here, - const base::Closure& request, - const base::Closure& reply) { - base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); - base::SequencedWorkerPool::SequenceToken token = - pool->GetNamedSequenceToken(Database::kDatabaseSequenceToken); - return pool->GetSequencedTaskRunner(token)->PostTaskAndReply( - from_here, request, reply); -} - -scoped_ptr<Event> CreateExtensionEvent(const EventType type, - const base::Time& time, - const std::string& id, - const std::string& name, - const std::string& url, - const int location, - const std::string& version, - const std::string& description) { - events::ExtensionEvent event; - event.event_type = type; - event.time = static_cast<double>(time.ToInternalValue()); - event.extension_id = id; - event.extension_name = name; - event.extension_url = url; - event.extension_location = location; - event.extension_version = version; - event.extension_description = description; - scoped_ptr<base::DictionaryValue> value = event.ToValue(); - return scoped_ptr<Event>(new Event( - type, time, value.Pass())); -} - -scoped_ptr<Event> CreateRendererFailureEvent(const base::Time& time, - const EventType& type, - const std::string& url) { - events::RendererFailure event; - event.event_type = type; - event.time = static_cast<double>(time.ToInternalValue()); - event.url = url; - scoped_ptr<base::DictionaryValue> value = event.ToValue(); - return scoped_ptr<Event>(new Event(type, time, value.Pass())); -} - -scoped_ptr<Event> CreateUncleanExitEvent(const base::Time& time, - const std::string& profile_name) { - events::UncleanExit event; - event.event_type = EVENT_UNCLEAN_EXIT; - event.time = static_cast<double>(time.ToInternalValue()); - event.profile_name = profile_name; - scoped_ptr<base::DictionaryValue> value = event.ToValue(); - return scoped_ptr<Event>(new Event( - EVENT_UNCLEAN_EXIT, time, value.Pass())); -} - -scoped_ptr<Event> CreateChromeUpdateEvent(const base::Time& time, - const std::string& previous_version, - const std::string& current_version) { - events::ChromeUpdate event; - event.event_type = EVENT_CHROME_UPDATE; - event.time = static_cast<double>(time.ToInternalValue()); - event.previous_version = previous_version; - event.current_version = current_version; - scoped_ptr<base::DictionaryValue> value = event.ToValue(); - return scoped_ptr<Event>(new Event( - EVENT_CHROME_UPDATE, time, value.Pass())); -} - -} // namespace util -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/performance_monitor_util.h b/chrome/browser/performance_monitor/performance_monitor_util.h deleted file mode 100644 index 7ad35bc..0000000 --- a/chrome/browser/performance_monitor/performance_monitor_util.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_PERFORMANCE_MONITOR_UTIL_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_PERFORMANCE_MONITOR_UTIL_H_ - -#include "base/callback.h" -#include "base/time/time.h" -#include "base/tracked_objects.h" -#include "chrome/browser/performance_monitor/database.h" -#include "chrome/browser/performance_monitor/event.h" -#include "chrome/browser/performance_monitor/metric.h" -#include "chrome/common/extensions/extension_constants.h" - -namespace performance_monitor { -namespace util { - -// Posts |request| to the performance monitor database's sequenced thread. On -// completion |reply| is posted to the thread that called -// PostTaskToDatabaseThreadAndReply. -bool PostTaskToDatabaseThreadAndReply( - const tracked_objects::Location& from_here, - const base::Closure& request, - const base::Closure& reply); - -// These are a collection of methods designed to create an event to store the -// pertinent information, given all the fields. Please use these methods to -// create any PerformanceMonitor events, as this will ensure strong-typing -// guards that performance_monitor::Event() will not. -scoped_ptr<Event> CreateExtensionEvent(const EventType type, - const base::Time& time, - const std::string& id, - const std::string& name, - const std::string& url, - const int location, - const std::string& version, - const std::string& description); - -scoped_ptr<Event> CreateRendererFailureEvent(const base::Time& time, - const EventType& type, - const std::string& url); - -scoped_ptr<Event> CreateUncleanExitEvent(const base::Time& time, - const std::string& profile_name); - -scoped_ptr<Event> CreateChromeUpdateEvent(const base::Time& time, - const std::string& previous_version, - const std::string& current_version); - -} // namespace util -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_PERFORMANCE_MONITOR_UTIL_H_ diff --git a/chrome/browser/performance_monitor/process_metrics_history.cc b/chrome/browser/performance_monitor/process_metrics_history.cc index 7c724e0..30bd921 100644 --- a/chrome/browser/performance_monitor/process_metrics_history.cc +++ b/chrome/browser/performance_monitor/process_metrics_history.cc @@ -8,7 +8,6 @@ #include "base/metrics/histogram.h" #include "base/process/process_metrics.h" -#include "chrome/browser/performance_monitor/constants.h" #include "chrome/browser/performance_monitor/process_metrics_history.h" #if defined(OS_MACOSX) #include "content/public/browser/browser_child_process_host.h" @@ -17,6 +16,10 @@ namespace performance_monitor { +// If a process is consistently above this CPU utilization percentage over time, +// we consider it as high and may take action. +const float kHighCPUUtilizationThreshold = 90.0f; + ProcessMetricsHistory::ProcessMetricsHistory() : process_handle_(0), process_type_(content::PROCESS_TYPE_UNKNOWN), diff --git a/chrome/browser/performance_monitor/startup_timer.cc b/chrome/browser/performance_monitor/startup_timer.cc deleted file mode 100644 index 8948252..0000000 --- a/chrome/browser/performance_monitor/startup_timer.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/performance_monitor/startup_timer.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/performance_monitor/database.h" -#include "chrome/browser/performance_monitor/performance_monitor.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" - -namespace performance_monitor { - -namespace { -// Needed because Database::AddMetric is overloaded, so base::Bind doesn't work. -void AddMetricToDatabaseOnBackgroundThread(Database* database, - const Metric& metric) { - database->AddMetric(metric); -} - -} // namespace - -// static -StartupTimer* StartupTimer::g_startup_timer_ = NULL; - -StartupTimer::StartupTimer() : startup_begin_(base::TimeTicks::Now()), - startup_type_(STARTUP_NORMAL), - performance_monitor_initialized_(false) { - CHECK(!g_startup_timer_); - g_startup_timer_ = this; - - // We need this check because, under certain rare circumstances, - // NotificationService::current() will return null, and this will cause a - // segfault in NotificationServiceImpl::AddObserver(). Currently, this only - // happens as a result of the child process launched by BrowserMainTest. - // WarmConnectionFieldTrial_Invalid. - if (content::NotificationService::current()) { - registrar_.Add(this, chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, - content::NotificationService::AllSources()); - } -} - -StartupTimer::~StartupTimer() { - DCHECK(this == g_startup_timer_); - g_startup_timer_ = NULL; -} - -bool StartupTimer::SignalStartupComplete(StartupType startup_type) { - DCHECK(elapsed_startup_time_ == base::TimeDelta()); - - startup_type_ = startup_type; - - elapsed_startup_time_ = - base::TimeTicks::Now() - total_pause_ - startup_begin_; - - if (performance_monitor_initialized_) - InsertElapsedStartupTime(); - - return true; -} - -// static -void StartupTimer::PauseTimer() { - // Check that the timer is not already paused. - DCHECK(g_startup_timer_->pause_started_ == base::TimeTicks()); - - g_startup_timer_->pause_started_ = base::TimeTicks::Now(); -} - -// static -void StartupTimer::UnpauseTimer() { - // Check that the timer has been paused. - DCHECK(g_startup_timer_->pause_started_ != base::TimeTicks()); - - g_startup_timer_->total_pause_ += base::TimeTicks::Now() - - g_startup_timer_->pause_started_; - - g_startup_timer_->pause_started_ = base::TimeTicks(); -} - -void StartupTimer::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - CHECK(type == chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED); - performance_monitor_initialized_ = true; - - if (PerformanceMonitor::GetInstance()->database_logging_enabled()) { - if (elapsed_startup_time_ != base::TimeDelta()) - InsertElapsedStartupTime(); - if (elapsed_session_restore_times_.size()) - InsertElapsedSessionRestoreTime(); - } -} - -// static -void StartupTimer::SetElapsedSessionRestoreTime( - const base::TimeDelta& elapsed_session_restore_time) { - if (PerformanceMonitor::GetInstance()->database_logging_enabled()) { - g_startup_timer_->elapsed_session_restore_times_.push_back( - elapsed_session_restore_time); - - if (g_startup_timer_->performance_monitor_initialized_) - g_startup_timer_->InsertElapsedSessionRestoreTime(); - } -} - -void StartupTimer::InsertElapsedStartupTime() { - content::BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind( - &AddMetricToDatabaseOnBackgroundThread, - base::Unretained(PerformanceMonitor::GetInstance()->database()), - Metric(startup_type_ == STARTUP_NORMAL ? METRIC_STARTUP_TIME - : METRIC_TEST_STARTUP_TIME, - base::Time::Now(), - static_cast<double>( - elapsed_startup_time_.ToInternalValue())))); -} - -void StartupTimer::InsertElapsedSessionRestoreTime() { - for (std::vector<base::TimeDelta>::const_iterator iter = - elapsed_session_restore_times_.begin(); - iter != elapsed_session_restore_times_.end(); ++iter) { - content::BrowserThread::PostBlockingPoolSequencedTask( - Database::kDatabaseSequenceToken, - FROM_HERE, - base::Bind( - &AddMetricToDatabaseOnBackgroundThread, - base::Unretained(PerformanceMonitor::GetInstance()->database()), - Metric(METRIC_SESSION_RESTORE_TIME, - base::Time::Now(), - static_cast<double>(iter->ToInternalValue())))); - } -} - -} // namespace performance_monitor diff --git a/chrome/browser/performance_monitor/startup_timer.h b/chrome/browser/performance_monitor/startup_timer.h deleted file mode 100644 index fc32a320..0000000 --- a/chrome/browser/performance_monitor/startup_timer.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_STARTUP_TIMER_H_ -#define CHROME_BROWSER_PERFORMANCE_MONITOR_STARTUP_TIMER_H_ - -#include "base/time/time.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" - -namespace performance_monitor { - -// This class is responsible for recording the startup and session restore times -// (if applicable) for PerformanceMonitor. This allows us to initialize this -// relatively small object early in the startup process, and start the whole of -// PerformanceMonitor at a later time. StartupTimer will record the times and -// insert them into PerformanceMonitor's database. -class StartupTimer : public content::NotificationObserver { - public: - // Indicates the type of startup; i.e. either a normal startup or a testing - // environment. - enum StartupType { - STARTUP_NORMAL, - STARTUP_TEST - }; - - StartupTimer(); - virtual ~StartupTimer(); - - // Inform StartupTimer that the startup process has been completed; stop the - // timer. Returns false if the timer has already stopped. - bool SignalStartupComplete(StartupType startup_type); - - // Pauses the timer until UnpauseTimer() is called; any time spent within a - // pause does not count towards the measured startup time. This will DCHECK if - // PauseTimer() is called while paused or UnpauseTimer() is called while - // unpaused. - static void PauseTimer(); - static void UnpauseTimer(); - - // content::NotificationObserver - // We keep track of whether or not PerformanceMonitor has been started via - // the PERFORMANCE_MONITOR_INITIALIZED notification; we need to know this so - // we know when to insert startup data into the database. We either insert - // data as we gather it (if PerformanceMonitor is started prior to data - // collection) or at the notification (if PerformanceMonitor is started - // later). - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - static void SetElapsedSessionRestoreTime( - const base::TimeDelta& elapsed_session_restore_time); - - private: - // Insert the elapsed time measures into PerformanceMonitor's database. - void InsertElapsedStartupTime(); - void InsertElapsedSessionRestoreTime(); - - // The time at which the startup process begins (the creation of - // ChromeBrowserMain). - base::TimeTicks startup_begin_; - - // The time at which the timer was most recently paused, or null if the timer - // is not currently paused. - base::TimeTicks pause_started_; - - // The total duration for which the timer has been paused. - base::TimeDelta total_pause_; - - // A flag of whether or not this was a "normal" startup (e.g. whether or not - // this was in a testing environment, which would change the startup time - // values). If it is not a normal startup, we use a different metric. - StartupType startup_type_; - - // The total duration of the startup process, minus any pauses. - base::TimeDelta elapsed_startup_time_; - - // The total duration of the session restore(s), if any occurred. This is - // independent of the startup time, because: - // - If the user has auto-restore on, the restore is synchronous, and we pause - // the startup timer during the session restore; the restore will not - // interfere with startup timing. - // - If Chrome crashed and the user chooses to restore the crashed session, - // then the startup is already completed; the restore will not interfere - // with startup timing. - std::vector<base::TimeDelta> elapsed_session_restore_times_; - - // Flag whether or not PerformanceMonitor has been fully started. - bool performance_monitor_initialized_; - - content::NotificationRegistrar registrar_; - - // The singleton of this class. - static StartupTimer* g_startup_timer_; - - DISALLOW_COPY_AND_ASSIGN(StartupTimer); -}; - -} // namespace performance_monitor - -#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_STARTUP_TIMER_H_ |