| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <algorithm> | |
| 6 #include <string> | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/file_path.h" | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/perftimer.h" | |
| 12 #include "base/shared_memory.h" | |
| 13 #include "base/stringprintf.h" | |
| 14 #include "base/test/test_file_util.h" | |
| 15 #include "chrome/browser/visitedlink/visitedlink_master.h" | |
| 16 #include "googleurl/src/gurl.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 using base::TimeDelta; | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 // how we generate URLs, note that the two strings should be the same length | |
| 24 const int add_count = 10000; | |
| 25 const int load_test_add_count = 250000; | |
| 26 const char added_prefix[] = "http://www.google.com/stuff/something/foo?session=8
5025602345625&id=1345142319023&seq="; | |
| 27 const char unadded_prefix[] = "http://www.google.org/stuff/something/foo?session
=39586739476365&id=2347624314402&seq="; | |
| 28 | |
| 29 // Returns a URL with the given prefix and index | |
| 30 GURL TestURL(const char* prefix, int i) { | |
| 31 return GURL(base::StringPrintf("%s%d", prefix, i)); | |
| 32 } | |
| 33 | |
| 34 // We have no slaves, so all methods on this listener are a no-ops. | |
| 35 class DummyVisitedLinkEventListener : public VisitedLinkMaster::Listener { | |
| 36 public: | |
| 37 DummyVisitedLinkEventListener() {} | |
| 38 virtual void NewTable(base::SharedMemory* table) {} | |
| 39 virtual void Add(VisitedLinkCommon::Fingerprint) {} | |
| 40 virtual void Reset() {} | |
| 41 | |
| 42 static DummyVisitedLinkEventListener* GetInstance() { | |
| 43 static DummyVisitedLinkEventListener instance; | |
| 44 return &instance; | |
| 45 } | |
| 46 }; | |
| 47 | |
| 48 | |
| 49 // this checks IsVisited for the URLs starting with the given prefix and | |
| 50 // within the given range | |
| 51 void CheckVisited(VisitedLinkMaster& master, const char* prefix, | |
| 52 int begin, int end) { | |
| 53 for (int i = begin; i < end; i++) | |
| 54 master.IsVisited(TestURL(prefix, i)); | |
| 55 } | |
| 56 | |
| 57 // Fills that master's table with URLs starting with the given prefix and | |
| 58 // within the given range | |
| 59 void FillTable(VisitedLinkMaster& master, const char* prefix, | |
| 60 int begin, int end) { | |
| 61 for (int i = begin; i < end; i++) | |
| 62 master.AddURL(TestURL(prefix, i)); | |
| 63 } | |
| 64 | |
| 65 class VisitedLink : public testing::Test { | |
| 66 protected: | |
| 67 FilePath db_path_; | |
| 68 virtual void SetUp() { | |
| 69 ASSERT_TRUE(file_util::CreateTemporaryFile(&db_path_)); | |
| 70 } | |
| 71 virtual void TearDown() { | |
| 72 file_util::Delete(db_path_, false); | |
| 73 } | |
| 74 }; | |
| 75 | |
| 76 } // namespace | |
| 77 | |
| 78 // This test tests adding many things to a database, and how long it takes | |
| 79 // to query the database with different numbers of things in it. The time | |
| 80 // is the total time to do all the operations, and as such, it is only | |
| 81 // useful for a regression test. If there is a regression, it might be | |
| 82 // useful to make another set of tests to test these things in isolation. | |
| 83 TEST_F(VisitedLink, TestAddAndQuery) { | |
| 84 // init | |
| 85 VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), | |
| 86 NULL, true, db_path_, 0); | |
| 87 ASSERT_TRUE(master.Init()); | |
| 88 | |
| 89 PerfTimeLogger timer("Visited_link_add_and_query"); | |
| 90 | |
| 91 // first check without anything in the table | |
| 92 CheckVisited(master, added_prefix, 0, add_count); | |
| 93 | |
| 94 // now fill half the table | |
| 95 const int half_size = add_count / 2; | |
| 96 FillTable(master, added_prefix, 0, half_size); | |
| 97 | |
| 98 // check the table again, half of these URLs will be visited, the other half | |
| 99 // will not | |
| 100 CheckVisited(master, added_prefix, 0, add_count); | |
| 101 | |
| 102 // fill the rest of the table | |
| 103 FillTable(master, added_prefix, half_size, add_count); | |
| 104 | |
| 105 // check URLs, doing half visited, half unvisited | |
| 106 CheckVisited(master, added_prefix, 0, add_count); | |
| 107 CheckVisited(master, unadded_prefix, 0, add_count); | |
| 108 } | |
| 109 | |
| 110 // Tests how long it takes to write and read a large database to and from disk. | |
| 111 TEST_F(VisitedLink, TestLoad) { | |
| 112 // create a big DB | |
| 113 { | |
| 114 PerfTimeLogger table_initialization_timer("Table_initialization"); | |
| 115 | |
| 116 VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), | |
| 117 NULL, true, db_path_, 0); | |
| 118 | |
| 119 // time init with empty table | |
| 120 PerfTimeLogger initTimer("Empty_visited_link_init"); | |
| 121 bool success = master.Init(); | |
| 122 initTimer.Done(); | |
| 123 ASSERT_TRUE(success); | |
| 124 | |
| 125 // add a bunch of stuff | |
| 126 // TODO(maruel): This is very inefficient because the file gets rewritten | |
| 127 // many time and this is the actual bottleneck of this test. The file should | |
| 128 // only get written that the end of the FillTable call, not 4169(!) times. | |
| 129 FillTable(master, added_prefix, 0, load_test_add_count); | |
| 130 | |
| 131 // time writing the file out out | |
| 132 PerfTimeLogger flushTimer("Visited_link_database_flush"); | |
| 133 master.RewriteFile(); | |
| 134 // TODO(maruel): Without calling FlushFileBuffers(master.file_); you don't | |
| 135 // know really how much time it took to write the file. | |
| 136 flushTimer.Done(); | |
| 137 | |
| 138 table_initialization_timer.Done(); | |
| 139 } | |
| 140 | |
| 141 // test loading the DB back, we do this several times since the flushing is | |
| 142 // not very reliable. | |
| 143 const int load_count = 5; | |
| 144 std::vector<double> cold_load_times; | |
| 145 std::vector<double> hot_load_times; | |
| 146 for (int i = 0; i < load_count; i++) { | |
| 147 // make sure the file has to be re-loaded | |
| 148 file_util::EvictFileFromSystemCache(db_path_); | |
| 149 | |
| 150 // cold load (no OS cache, hopefully) | |
| 151 { | |
| 152 PerfTimer cold_timer; | |
| 153 | |
| 154 VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), | |
| 155 NULL, | |
| 156 true, | |
| 157 db_path_, | |
| 158 0); | |
| 159 bool success = master.Init(); | |
| 160 TimeDelta elapsed = cold_timer.Elapsed(); | |
| 161 ASSERT_TRUE(success); | |
| 162 | |
| 163 cold_load_times.push_back(elapsed.InMillisecondsF()); | |
| 164 } | |
| 165 | |
| 166 // hot load (with OS caching the file in memory) | |
| 167 { | |
| 168 PerfTimer hot_timer; | |
| 169 | |
| 170 VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(), | |
| 171 NULL, | |
| 172 true, | |
| 173 db_path_, | |
| 174 0); | |
| 175 bool success = master.Init(); | |
| 176 TimeDelta elapsed = hot_timer.Elapsed(); | |
| 177 ASSERT_TRUE(success); | |
| 178 | |
| 179 hot_load_times.push_back(elapsed.InMillisecondsF()); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 // We discard the max and return the average time. | |
| 184 cold_load_times.erase(std::max_element(cold_load_times.begin(), | |
| 185 cold_load_times.end())); | |
| 186 hot_load_times.erase(std::max_element(hot_load_times.begin(), | |
| 187 hot_load_times.end())); | |
| 188 | |
| 189 double cold_sum = 0, hot_sum = 0; | |
| 190 for (int i = 0; i < static_cast<int>(cold_load_times.size()); i++) { | |
| 191 cold_sum += cold_load_times[i]; | |
| 192 hot_sum += hot_load_times[i]; | |
| 193 } | |
| 194 LogPerfResult("Visited_link_cold_load_time", | |
| 195 cold_sum / cold_load_times.size(), "ms"); | |
| 196 LogPerfResult("Visited_link_hot_load_time", | |
| 197 hot_sum / hot_load_times.size(), "ms"); | |
| 198 } | |
| OLD | NEW |