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/files/file_path.h"
     10 #include "base/files/file_util.h"
     11 #include "base/memory/shared_memory.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/test/perf_log.h"
     14 #include "base/test/perf_time_logger.h"
     15 #include "base/test/test_file_util.h"
     16 #include "base/timer/elapsed_timer.h"
     17 #include "components/visitedlink/browser/visitedlink_master.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 #include "url/gurl.h"
     20 
     21 using base::TimeDelta;
     22 
     23 namespace visitedlink {
     24 
     25 namespace {
     26 
     27 // how we generate URLs, note that the two strings should be the same length
     28 const int add_count = 10000;
     29 const int load_test_add_count = 250000;
     30 const char added_prefix[] = "http://www.google.com/stuff/something/foo?session=85025602345625&id=1345142319023&seq=";
     31 const char unadded_prefix[] = "http://www.google.org/stuff/something/foo?session=39586739476365&id=2347624314402&seq=";
     32 
     33 // Returns a URL with the given prefix and index
     34 GURL TestURL(const char* prefix, int i) {
     35   return GURL(base::StringPrintf("%s%d", prefix, i));
     36 }
     37 
     38 // We have no slaves, so all methods on this listener are a no-ops.
     39 class DummyVisitedLinkEventListener : public VisitedLinkMaster::Listener {
     40  public:
     41   DummyVisitedLinkEventListener() {}
     42   virtual void NewTable(base::SharedMemory* table) OVERRIDE {}
     43   virtual void Add(VisitedLinkCommon::Fingerprint) OVERRIDE {}
     44   virtual void Reset() OVERRIDE {}
     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   base::FilePath db_path_;
     67   virtual void SetUp() {
     68     ASSERT_TRUE(base::CreateTemporaryFile(&db_path_));
     69   }
     70   virtual void TearDown() {
     71     base::DeleteFile(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(new DummyVisitedLinkEventListener(),
     85                            NULL, true, true, db_path_, 0);
     86   ASSERT_TRUE(master.Init());
     87 
     88   base::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     base::PerfTimeLogger table_initialization_timer("Table_initialization");
    114 
    115     VisitedLinkMaster master(new DummyVisitedLinkEventListener(),
    116                              NULL, true, true, db_path_, 0);
    117 
    118     // time init with empty table
    119     base::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     base::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     base::EvictFileFromSystemCache(db_path_);
    148 
    149     // cold load (no OS cache, hopefully)
    150     {
    151       base::ElapsedTimer cold_timer;
    152 
    153       VisitedLinkMaster master(new DummyVisitedLinkEventListener(),
    154                                NULL,
    155                                true,
    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       base::ElapsedTimer hot_timer;
    169 
    170       VisitedLinkMaster master(new DummyVisitedLinkEventListener(),
    171                                NULL,
    172                                true,
    173                                true,
    174                                db_path_,
    175                                0);
    176       bool success = master.Init();
    177       TimeDelta elapsed = hot_timer.Elapsed();
    178       ASSERT_TRUE(success);
    179 
    180       hot_load_times.push_back(elapsed.InMillisecondsF());
    181     }
    182   }
    183 
    184   // We discard the max and return the average time.
    185   cold_load_times.erase(std::max_element(cold_load_times.begin(),
    186                                          cold_load_times.end()));
    187   hot_load_times.erase(std::max_element(hot_load_times.begin(),
    188                                         hot_load_times.end()));
    189 
    190   double cold_sum = 0, hot_sum = 0;
    191   for (int i = 0; i < static_cast<int>(cold_load_times.size()); i++) {
    192     cold_sum += cold_load_times[i];
    193     hot_sum += hot_load_times[i];
    194   }
    195   base::LogPerfResult(
    196       "Visited_link_cold_load_time", cold_sum / cold_load_times.size(), "ms");
    197   base::LogPerfResult(
    198       "Visited_link_hot_load_time", hot_sum / hot_load_times.size(), "ms");
    199 }
    200 
    201 }  // namespace visitedlink
    202