diff options
Diffstat (limited to 'chrome/browser/visitedlink/visitedlink_perftest.cc')
-rw-r--r-- | chrome/browser/visitedlink/visitedlink_perftest.cc | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/chrome/browser/visitedlink/visitedlink_perftest.cc b/chrome/browser/visitedlink/visitedlink_perftest.cc new file mode 100644 index 0000000..7d44b59 --- /dev/null +++ b/chrome/browser/visitedlink/visitedlink_perftest.cc @@ -0,0 +1,207 @@ +// Copyright (c) 2010 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/file_path.h" +#include "base/file_util.h" +#include "base/perftimer.h" +#include "base/shared_memory.h" +#include "base/string_util.h" +#include "base/test/test_file_util.h" +#include "chrome/browser/visitedlink/visitedlink_master.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::TimeDelta; + +namespace { + +// how we generate URLs, note that the two strings should be the same length +const int add_count = 10000; +const int load_test_add_count = 250000; +const char added_prefix[] = "http://www.google.com/stuff/something/foo?session=85025602345625&id=1345142319023&seq="; +const char unadded_prefix[] = "http://www.google.org/stuff/something/foo?session=39586739476365&id=2347624314402&seq="; + +// Returns a URL with the given prefix and index +GURL TestURL(const char* prefix, int i) { + return GURL(StringPrintf("%s%d", prefix, i)); +} + +// We have no slaves, so all methods on this listener are a no-ops. +class DummyVisitedLinkEventListener : public VisitedLinkMaster::Listener { + public: + DummyVisitedLinkEventListener() {} + virtual void NewTable(base::SharedMemory* table) {} + virtual void Add(VisitedLinkCommon::Fingerprint) {} + virtual void Reset() {} + + static DummyVisitedLinkEventListener* GetInstance() { + static DummyVisitedLinkEventListener instance; + return &instance; + } +}; + + +// Call at the beginning of the test to retrieve the database name. +void InitDBName(std::wstring* db_name) { + FilePath db_path; + ASSERT_TRUE(file_util::GetCurrentDirectory(&db_path)); + db_path = db_path.AppendASCII("TempVisitedLinks"); + *db_name = db_path.ToWStringHack(); +} + +// this checks IsVisited for the URLs starting with the given prefix and +// within the given range +void CheckVisited(VisitedLinkMaster& master, const char* prefix, + int begin, int end) { + for (int i = begin; i < end; i++) + master.IsVisited(TestURL(prefix, i)); +} + +// Fills that master's table with URLs starting with the given prefix and +// within the given range +void FillTable(VisitedLinkMaster& master, const char* prefix, + int begin, int end) { + for (int i = begin; i < end; i++) + master.AddURL(TestURL(prefix, i)); +} + +class VisitedLink : public testing::Test { + protected: + std::wstring db_name_; + virtual void SetUp() { + InitDBName(&db_name_); + file_util::Delete(db_name_, false); + } + virtual void TearDown() { + file_util::Delete(db_name_, false); + } +}; + +} // namespace + +// This test tests adding many things to a database, and how long it takes +// to query the database with different numbers of things in it. The time +// is the total time to do all the operations, and as such, it is only +// useful for a regression test. If there is a regression, it might be +// useful to make another set of tests to test these things in isolation. +TEST_F(VisitedLink, TestAddAndQuery) { + // init + VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), + NULL, true, FilePath(db_name_), 0); + ASSERT_TRUE(master.Init()); + + PerfTimeLogger timer("Visited_link_add_and_query"); + + // first check without anything in the table + CheckVisited(master, added_prefix, 0, add_count); + + // now fill half the table + const int half_size = add_count / 2; + FillTable(master, added_prefix, 0, half_size); + + // check the table again, half of these URLs will be visited, the other half + // will not + CheckVisited(master, added_prefix, 0, add_count); + + // fill the rest of the table + FillTable(master, added_prefix, half_size, add_count); + + // check URLs, doing half visited, half unvisited + CheckVisited(master, added_prefix, 0, add_count); + CheckVisited(master, unadded_prefix, 0, add_count); +} + +// Tests how long it takes to write and read a large database to and from disk. +TEST_F(VisitedLink, TestLoad) { + // create a big DB + { + PerfTimeLogger table_initialization_timer("Table_initialization"); + + VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), + NULL, true, FilePath(db_name_), 0); + + // time init with empty table + PerfTimeLogger initTimer("Empty_visited_link_init"); + bool success = master.Init(); + initTimer.Done(); + ASSERT_TRUE(success); + + // add a bunch of stuff + // TODO(maruel): This is very inefficient because the file gets rewritten + // many time and this is the actual bottleneck of this test. The file should + // only get written that the end of the FillTable call, not 4169(!) times. + FillTable(master, added_prefix, 0, load_test_add_count); + + // time writing the file out out + PerfTimeLogger flushTimer("Visited_link_database_flush"); + master.RewriteFile(); + // TODO(maruel): Without calling FlushFileBuffers(master.file_); you don't + // know really how much time it took to write the file. + flushTimer.Done(); + + table_initialization_timer.Done(); + } + + // test loading the DB back, we do this several times since the flushing is + // not very reliable. + const int load_count = 5; + std::vector<double> cold_load_times; + std::vector<double> hot_load_times; + for (int i = 0; i < load_count; i++) { + // make sure the file has to be re-loaded + file_util::EvictFileFromSystemCache( + FilePath::FromWStringHack(std::wstring(db_name_))); + + // cold load (no OS cache, hopefully) + { + PerfTimer cold_timer; + + VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), + NULL, + true, + FilePath(db_name_), + 0); + bool success = master.Init(); + TimeDelta elapsed = cold_timer.Elapsed(); + ASSERT_TRUE(success); + + cold_load_times.push_back(elapsed.InMillisecondsF()); + } + + // hot load (with OS caching the file in memory) + { + PerfTimer hot_timer; + + VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), + NULL, + true, + FilePath(db_name_), + 0); + bool success = master.Init(); + TimeDelta elapsed = hot_timer.Elapsed(); + ASSERT_TRUE(success); + + hot_load_times.push_back(elapsed.InMillisecondsF()); + } + } + + // We discard the max and return the average time. + cold_load_times.erase(std::max_element(cold_load_times.begin(), + cold_load_times.end())); + hot_load_times.erase(std::max_element(hot_load_times.begin(), + hot_load_times.end())); + + double cold_sum = 0, hot_sum = 0; + for (int i = 0; i < static_cast<int>(cold_load_times.size()); i++) { + cold_sum += cold_load_times[i]; + hot_sum += hot_load_times[i]; + } + LogPerfResult("Visited_link_cold_load_time", + cold_sum / cold_load_times.size(), "ms"); + LogPerfResult("Visited_link_hot_load_time", + hot_sum / hot_load_times.size(), "ms"); +} |