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 |