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