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