summaryrefslogtreecommitdiffstats
path: root/chrome/browser/performance_monitor
diff options
context:
space:
mode:
authoreaugusti@chromium.org <eaugusti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-17 21:07:18 +0000
committereaugusti@chromium.org <eaugusti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-17 21:07:18 +0000
commit9578c70a20f75ba2eaf0b78050144ff7834b3578 (patch)
tree162c2bfb466b1c5f0b4ce5d5094a8fcbe960c1cb /chrome/browser/performance_monitor
parent910f0f34f7a420a476326d3eebb26feed7d862a3 (diff)
downloadchromium_src-9578c70a20f75ba2eaf0b78050144ff7834b3578.zip
chromium_src-9578c70a20f75ba2eaf0b78050144ff7834b3578.tar.gz
chromium_src-9578c70a20f75ba2eaf0b78050144ff7834b3578.tar.bz2
Chrome Performance Monitor Database -- Events
Extends the core performance monitor database to support adding and querying events. BUG=130212 Review URL: https://chromiumcodereview.appspot.com/10539140 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142652 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/performance_monitor')
-rw-r--r--chrome/browser/performance_monitor/database.cc137
-rw-r--r--chrome/browser/performance_monitor/database.h40
-rw-r--r--chrome/browser/performance_monitor/database_unittest.cc124
3 files changed, 266 insertions, 35 deletions
diff --git a/chrome/browser/performance_monitor/database.cc b/chrome/browser/performance_monitor/database.cc
index ffc37df..be8b0f2 100644
--- a/chrome/browser/performance_monitor/database.cc
+++ b/chrome/browser/performance_monitor/database.cc
@@ -7,9 +7,12 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/format_macros.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -26,6 +29,12 @@ const char kActiveIntervalDb[] = "Active Interval";
const char kMetricDb[] = "Metrics";
const char kDelimiter = '!';
+// 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.
+};
+
// If the db is quiet for this number of microseconds, then it is considered
// down.
const base::TimeDelta kActiveIntervalTimeout = base::TimeDelta::FromSeconds(5);
@@ -34,6 +43,21 @@ const base::TimeDelta kActiveIntervalTimeout = base::TimeDelta::FromSeconds(5);
std::string CreateActiveIntervalKey(const base::Time& time) {
return StringPrintf("%016" PRId64, time.ToInternalValue());
}
+
+// Create the database key for a particular event.
+std::string CreateEventKey(const base::Time& time,
+ performance_monitor::EventType type) {
+ return StringPrintf("%016" PRId64 "%c%04d", time.ToInternalValue(),
+ kDelimiter, static_cast<int>(type));
+}
+
+int EventKeyToType(const std::string& event_key) {
+ std::vector<std::string> split;
+ base::SplitString(event_key, kDelimiter, &split);
+ int event_type;
+ base::StringToInt(split[EVENT_TYPE], &event_type);
+ return event_type;
+}
} // namespace
namespace performance_monitor {
@@ -52,11 +76,23 @@ TimeRange::~TimeRange() {
base::Time Database::SystemClock::GetTime() {
return base::Time::Now();
}
+
+// Static
+scoped_refptr<Database> Database::Create(FilePath path) {
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (path.empty()) {
+ CHECK(PathService::Get(chrome::DIR_USER_DATA, &path));
+ path = path.AppendASCII(kDbDir);
+ }
+ if (!file_util::DirectoryExists(path) && !file_util::CreateDirectory(path))
+ return scoped_refptr<Database>();
+ return scoped_refptr<Database>(new Database(path));
+}
+
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);
+ leveldb::Status insert_status = state_db_->Put(write_options_, key, value);
return insert_status.ok();
}
@@ -67,16 +103,14 @@ std::string Database::GetStateValue(const std::string& key) {
return result;
}
-void Database::Clear() {
+bool Database::AddEvent(const Event& event) {
CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- metric_db_.reset();
- recent_db_.reset();
- state_db_.reset();
- active_interval_db_.reset();
- // Recursively delete all the databases.
- if (!file_util::Delete(path_, true /* recursive */) ||
- !file_util::CreateDirectory(path_))
- LOG(ERROR) << "Failed to clear the performance monitor databases.";
+ UpdateActiveInterval();
+ std::string value;
+ base::JSONWriter::Write(event.data(), &value);
+ std::string key = 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,
@@ -112,10 +146,66 @@ std::vector<TimeRange> Database::GetActiveIntervals(const base::Time& start,
return results;
}
+Database::EventList Database::GetEvents(EventType type, const base::Time& start,
+ const base::Time& end) {
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ EventList events;
+ std::string start_key = CreateEventKey(start, EVENT_UNDEFINED);
+ std::string end_key = CreateEventKey(end, EVENT_UNDEFINED);
+ 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) {
+ int key_type = EventKeyToType(it->key().ToString());
+ if (key_type != type)
+ continue;
+ }
+ base::DictionaryValue* dict = NULL;
+ if (!base::JSONReader::Read(
+ it->value().ToString())->GetAsDictionary(&dict)) {
+ LOG(ERROR) << "Unable to convert database event to JSON.";
+ continue;
+ }
+ scoped_ptr<Event> event =
+ Event::FromValue(scoped_ptr<base::DictionaryValue>(dict));
+ if (!event.get())
+ continue;
+ events.push_back(linked_ptr<Event>(event.release()));
+ }
+ 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 = CreateEventKey(start, EVENT_UNDEFINED);
+ std::string end_key = CreateEventKey(end, EVENT_UNDEFINED);
+ scoped_ptr<leveldb::Iterator> it(event_db_->NewIterator(read_options_));
+ for (it->Seek(start_key);
+ it->Valid() && it->key().ToString() <= end_key;
+ it->Next()) {
+ int key_type = EventKeyToType(it->key().ToString());
+ results.insert(static_cast<EventType>(key_type));
+ }
+ return results;
+}
+
Database::Database(const FilePath& path)
: path_(path),
read_options_(leveldb::ReadOptions()),
write_options_(leveldb::WriteOptions()) {
+ InitDBs();
+ clock_ = scoped_ptr<Clock>(new SystemClock());
+}
+
+Database::~Database() {
+ Close();
+}
+
+void Database::InitDBs() {
+ CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
leveldb::DB* new_db = NULL;
leveldb::Options open_options;
open_options.create_if_missing = true;
@@ -133,6 +223,9 @@ Database::Database(const FilePath& path)
leveldb::DB::Open(open_options, path_.AppendASCII(kMetricDb).value(),
&new_db);
metric_db_ = scoped_ptr<leveldb::DB>(new_db);
+ leveldb::DB::Open(open_options, path_.AppendASCII(kEventDb).value(),
+ &new_db);
+ event_db_ = scoped_ptr<leveldb::DB>(new_db);
#elif defined(OS_WIN)
leveldb::DB::Open(open_options,
WideToUTF8(path_.AppendASCII(kRecentDb).value()), &new_db);
@@ -147,35 +240,19 @@ Database::Database(const FilePath& path)
leveldb::DB::Open(open_options,
WideToUTF8(path_.AppendASCII(kMetricDb).value()), &new_db);
metric_db_ = scoped_ptr<leveldb::DB>(new_db);
+ leveldb::DB::Open(open_options,
+ WideToUTF8(path_.AppendASCII(kEventDb).value()), &new_db);
+ event_db_ = scoped_ptr<leveldb::DB>(new_db);
#endif
- clock_ = scoped_ptr<Clock>(new SystemClock());
-}
-
-Database::~Database() {
- Close();
-}
-
-// Static
-scoped_refptr<Database> Database::Create(FilePath path) {
- CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (path.empty()) {
- CHECK(PathService::Get(chrome::DIR_USER_DATA, &path));
- path = path.AppendASCII(kDbDir);
- }
- if (!file_util::DirectoryExists(path) && !file_util::CreateDirectory(path))
- return scoped_refptr<Database>();
- return scoped_refptr<Database>(new Database(path));
}
bool Database::Close() {
CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
metric_db_.reset();
recent_db_.reset();
state_db_.reset();
active_interval_db_.reset();
start_time_key_.clear();
-
return true;
}
diff --git a/chrome/browser/performance_monitor/database.h b/chrome/browser/performance_monitor/database.h
index b938f84..b117417 100644
--- a/chrome/browser/performance_monitor/database.h
+++ b/chrome/browser/performance_monitor/database.h
@@ -7,14 +7,16 @@
#pragma once
#include <vector>
+#include <set>
#include <string>
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/linked_ptr.h"
#include "base/time.h"
+#include "chrome/browser/performance_monitor/event.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
namespace performance_monitor {
@@ -81,6 +83,9 @@ struct TimeRange {
// Value: Statistic
class Database : public base::RefCountedThreadSafe<Database> {
public:
+ typedef std::vector<linked_ptr<Event> > EventList;
+ typedef std::set<EventType> EventTypeSet;
+
// 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 {
@@ -98,12 +103,35 @@ class Database : public base::RefCountedThreadSafe<Database> {
std::string GetStateValue(const std::string& key);
- // Erase everything in the database. Warning - No undo!
- void Clear();
+ // 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.
+ EventList GetEvents(EventType type, const base::Time& start,
+ const base::Time& end);
+
+ EventList GetEvents(const base::Time& start, const base::Time& end) {
+ return GetEvents(EVENT_UNDEFINED, start, end);
+ }
+
+ EventList GetEvents(EventType type) {
+ return GetEvents(type, base::Time(), clock_->GetTime());
+ }
+
+ EventList 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());
+ }
// Returns the times for which there is data in the database.
std::vector<TimeRange> GetActiveIntervals(const base::Time& start,
- const base::Time& end);
+ const base::Time& end);
FilePath path() const { return path_; }
@@ -128,6 +156,8 @@ class Database : public base::RefCountedThreadSafe<Database> {
explicit Database(const FilePath& path);
virtual ~Database();
+ void InitDBs();
+
bool Close();
// Mark the database as being active for the current time.
@@ -152,6 +182,8 @@ class Database : public base::RefCountedThreadSafe<Database> {
scoped_ptr<leveldb::DB> metric_db_;
+ scoped_ptr<leveldb::DB> event_db_;
+
leveldb::ReadOptions read_options_;
leveldb::WriteOptions write_options_;
diff --git a/chrome/browser/performance_monitor/database_unittest.cc b/chrome/browser/performance_monitor/database_unittest.cc
index cfab99a..d54ced2 100644
--- a/chrome/browser/performance_monitor/database_unittest.cc
+++ b/chrome/browser/performance_monitor/database_unittest.cc
@@ -10,8 +10,12 @@
#include "base/memory/scoped_ptr.h"
#include "base/time.h"
#include "chrome/browser/performance_monitor/database.h"
+#include "chrome/browser/performance_monitor/performance_monitor_util.h"
+#include "chrome/common/extensions/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
+using extensions::Extension;
+
namespace performance_monitor {
// A clock that increments every access. Great for testing.
@@ -31,6 +35,54 @@ class TestingClock : public Database::Clock {
int64 counter_;
};
+class PerformanceMonitorDatabaseEventTest : public ::testing::Test {
+ protected:
+ PerformanceMonitorDatabaseEventTest() {
+ clock_ = new TestingClock();
+ file_util::CreateNewTempDirectory(FilePath::StringType(), &temp_path_);
+ db_ = Database::Create(temp_path_);
+ CHECK(db_.get());
+ db_->set_clock(scoped_ptr<Database::Clock>(clock_));
+ }
+
+ void SetUp() {
+ ASSERT_TRUE(db_);
+ 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_refptr<Database> db_;
+ Database::Clock* clock_;
+ FilePath temp_path_;
+ 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::CreateExtensionInstallEvent(
+ clock_->GetTime(), "a", "extension 1", "http://foo.com",
+ static_cast<int>(Extension::LOAD), "0.1", "Test Test");
+ install_event_2_ = util::CreateExtensionInstallEvent(
+ clock_->GetTime(), "b", "extension 2", "http://bar.com",
+ static_cast<int>(Extension::LOAD), "0.1", "Test Test");
+ uninstall_event_1_ = util::CreateExtensionUninstallEvent(
+ clock_->GetTime(), "a", "extension 1", "http://foo.com",
+ static_cast<int>(Extension::LOAD), "0.1", "Test Test");
+ uninstall_event_2_ = util::CreateExtensionUninstallEvent(
+ clock_->GetTime(), "b", "extension 2", "http://bar.com",
+ static_cast<int>(Extension::LOAD), "0.1", "Test Test");
+ }
+};
+
////// PerformanceMonitorDatabaseSetupTests ////////////////////////////////////
TEST(PerformanceMonitorDatabaseSetupTest, OpenCloseTest) {
FilePath alternate_path;
@@ -69,11 +121,81 @@ TEST(PerformanceMonitorDatabaseSetupTest, ActiveIntervalTest) {
ASSERT_TRUE(db_3);
std::vector<TimeRange> active_interval = db_3->GetActiveIntervals(start_time,
- end_time);
+ end_time);
ASSERT_EQ(active_interval.size(), static_cast<size_t>(2));
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);
}
+
+////// PerformanceMonitorDatabaseEventTests ////////////////////////////////////
+TEST_F(PerformanceMonitorDatabaseEventTest, GetAllEventsTest) {
+ std::vector<linked_ptr<Event> > 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(PerformanceMonitorDatabaseEventTest, GetAllEventTypesTest) {
+ std::set<EventType> 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::CreateRendererFreezeEvent(
+ clock_->GetTime(), "chrome://freeze");
+ db_->AddEvent(*crash_event.get());
+ std::vector<linked_ptr<Event> > 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) {
+ std::vector<linked_ptr<Event> > 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, GetUnusedEventType) {
+ std::vector<linked_ptr<Event> > events =
+ db_->GetEvents(EVENT_EXTENSION_UNLOAD);
+ ASSERT_TRUE(events.empty());
+ events = db_->GetEvents(EVENT_EXTENSION_UNLOAD,
+ 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::CreateExtensionInstallEvent(
+ clock_->GetTime(), "c", "test extension", "http://foo.com",
+ static_cast<int>(Extension::LOAD), "0.1", "Test Test");
+ scoped_ptr<Event> new_uninstall_event =
+ util::CreateExtensionUninstallEvent(
+ clock_->GetTime(), "c", "test extension", "http://foo.com",
+ static_cast<int>(Extension::LOAD), "0.1", "Test Test");
+ base::Time end_time = clock_->GetTime();
+ db_->AddEvent(*new_install_event.get());
+ db_->AddEvent(*new_uninstall_event.get());
+ std::vector<linked_ptr<Event> > 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()));
+}
} // namespace performance_monitor