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