Home | History | Annotate | Download | only in visitedlink
      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/string_util.h"
     14 #include "base/test/test_file_util.h"
     15 #include "chrome/browser/visitedlink/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=85025602345625&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 // this checks IsVisited for the URLs starting with the given prefix and
     49 // within the given range
     50 void CheckVisited(VisitedLinkMaster& master, const char* prefix,
     51                   int begin, int end) {
     52   for (int i = begin; i < end; i++)
     53     master.IsVisited(TestURL(prefix, i));
     54 }
     55 
     56 // Fills that master's table with URLs starting with the given prefix and
     57 // within the given range
     58 void FillTable(VisitedLinkMaster& master, const char* prefix,
     59                int begin, int end) {
     60   for (int i = begin; i < end; i++)
     61     master.AddURL(TestURL(prefix, i));
     62 }
     63 
     64 class VisitedLink : public testing::Test {
     65  protected:
     66   FilePath db_path_;
     67   virtual void SetUp() {
     68     ASSERT_TRUE(file_util::CreateTemporaryFile(&db_path_));
     69   }
     70   virtual void TearDown() {
     71     file_util::Delete(db_path_, false);
     72   }
     73 };
     74 
     75 } // namespace
     76 
     77 // This test tests adding many things to a database, and how long it takes
     78 // to query the database with different numbers of things in it. The time
     79 // is the total time to do all the operations, and as such, it is only
     80 // useful for a regression test. If there is a regression, it might be
     81 // useful to make another set of tests to test these things in isolation.
     82 TEST_F(VisitedLink, TestAddAndQuery) {
     83   // init
     84   VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
     85                            NULL, true, db_path_, 0);
     86   ASSERT_TRUE(master.Init());
     87 
     88   PerfTimeLogger timer("Visited_link_add_and_query");
     89 
     90   // first check without anything in the table
     91   CheckVisited(master, added_prefix, 0, add_count);
     92 
     93   // now fill half the table
     94   const int half_size = add_count / 2;
     95   FillTable(master, added_prefix, 0, half_size);
     96 
     97   // check the table again, half of these URLs will be visited, the other half
     98   // will not
     99   CheckVisited(master, added_prefix, 0, add_count);
    100 
    101   // fill the rest of the table
    102   FillTable(master, added_prefix, half_size, add_count);
    103 
    104   // check URLs, doing half visited, half unvisited
    105   CheckVisited(master, added_prefix, 0, add_count);
    106   CheckVisited(master, unadded_prefix, 0, add_count);
    107 }
    108 
    109 // Tests how long it takes to write and read a large database to and from disk.
    110 TEST_F(VisitedLink, TestLoad) {
    111   // create a big DB
    112   {
    113     PerfTimeLogger table_initialization_timer("Table_initialization");
    114 
    115     VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
    116                              NULL, true, db_path_, 0);
    117 
    118     // time init with empty table
    119     PerfTimeLogger initTimer("Empty_visited_link_init");
    120     bool success = master.Init();
    121     initTimer.Done();
    122     ASSERT_TRUE(success);
    123 
    124     // add a bunch of stuff
    125     // TODO(maruel): This is very inefficient because the file gets rewritten
    126     // many time and this is the actual bottleneck of this test. The file should
    127     // only get written that the end of the FillTable call, not 4169(!) times.
    128     FillTable(master, added_prefix, 0, load_test_add_count);
    129 
    130     // time writing the file out out
    131     PerfTimeLogger flushTimer("Visited_link_database_flush");
    132     master.RewriteFile();
    133     // TODO(maruel): Without calling FlushFileBuffers(master.file_); you don't
    134     // know really how much time it took to write the file.
    135     flushTimer.Done();
    136 
    137     table_initialization_timer.Done();
    138   }
    139 
    140   // test loading the DB back, we do this several times since the flushing is
    141   // not very reliable.
    142   const int load_count = 5;
    143   std::vector<double> cold_load_times;
    144   std::vector<double> hot_load_times;
    145   for (int i = 0; i < load_count; i++) {
    146     // make sure the file has to be re-loaded
    147     file_util::EvictFileFromSystemCache(db_path_);
    148 
    149     // cold load (no OS cache, hopefully)
    150     {
    151       PerfTimer cold_timer;
    152 
    153       VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
    154                                NULL,
    155                                true,
    156                                db_path_,
    157                                0);
    158       bool success = master.Init();
    159       TimeDelta elapsed = cold_timer.Elapsed();
    160       ASSERT_TRUE(success);
    161 
    162       cold_load_times.push_back(elapsed.InMillisecondsF());
    163     }
    164 
    165     // hot load (with OS caching the file in memory)
    166     {
    167       PerfTimer hot_timer;
    168 
    169       VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
    170                                NULL,
    171                                true,
    172                                db_path_,
    173                                0);
    174       bool success = master.Init();
    175       TimeDelta elapsed = hot_timer.Elapsed();
    176       ASSERT_TRUE(success);
    177 
    178       hot_load_times.push_back(elapsed.InMillisecondsF());
    179     }
    180   }
    181 
    182   // We discard the max and return the average time.
    183   cold_load_times.erase(std::max_element(cold_load_times.begin(),
    184                                          cold_load_times.end()));
    185   hot_load_times.erase(std::max_element(hot_load_times.begin(),
    186                                         hot_load_times.end()));
    187 
    188   double cold_sum = 0, hot_sum = 0;
    189   for (int i = 0; i < static_cast<int>(cold_load_times.size()); i++) {
    190     cold_sum += cold_load_times[i];
    191     hot_sum += hot_load_times[i];
    192   }
    193   LogPerfResult("Visited_link_cold_load_time",
    194                 cold_sum / cold_load_times.size(), "ms");
    195   LogPerfResult("Visited_link_hot_load_time",
    196                 hot_sum / hot_load_times.size(), "ms");
    197 }
    198