OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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 "components/omnibox/browser/history_quick_provider.h" |
| 6 |
| 7 #include <memory> |
| 8 #include <random> |
| 9 #include <string> |
| 10 |
| 11 #include "base/macros.h" |
| 12 #include "base/run_loop.h" |
| 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "components/history/core/browser/history_backend.h" |
| 15 #include "components/history/core/browser/history_database.h" |
| 16 #include "components/history/core/browser/history_service.h" |
| 17 #include "components/history/core/test/history_service_test_util.h" |
| 18 #include "components/omnibox/browser/fake_autocomplete_provider_client.h" |
| 19 #include "components/omnibox/browser/history_test_util.h" |
| 20 #include "components/omnibox/browser/in_memory_url_index_test_util.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 #include "testing/perf/perf_test.h" |
| 23 |
| 24 namespace history { |
| 25 |
| 26 namespace { |
| 27 |
| 28 // Not threadsafe. |
| 29 std::string GenerateFakeHashedString(size_t sym_count) { |
| 30 static constexpr char kSyms[] = |
| 31 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,/=+?#"; |
| 32 CR_DEFINE_STATIC_LOCAL(std::mt19937, engine, ()); |
| 33 std::uniform_int_distribution<size_t> index_distribution( |
| 34 0, arraysize(kSyms) - 2 /* trailing \0 */); |
| 35 |
| 36 std::string res; |
| 37 res.reserve(sym_count); |
| 38 |
| 39 std::generate_n(std::back_inserter(res), sym_count, [&index_distribution] { |
| 40 return kSyms[index_distribution(engine)]; |
| 41 }); |
| 42 |
| 43 return res; |
| 44 } |
| 45 |
| 46 URLRow GeneratePopularURLRow() { |
| 47 static constexpr char kPopularUrl[] = |
| 48 "http://long.popular_url_with.many_variations/"; |
| 49 |
| 50 constexpr size_t kFakeHashLength = 10; |
| 51 std::string fake_hash = GenerateFakeHashedString(kFakeHashLength); |
| 52 |
| 53 URLRow row{GURL(kPopularUrl + fake_hash)}; |
| 54 EXPECT_TRUE(row.url().is_valid()); |
| 55 row.set_title(base::UTF8ToUTF16("Page " + fake_hash)); |
| 56 row.set_visit_count(1); |
| 57 row.set_typed_count(1); |
| 58 row.set_last_visit(base::Time::Now() - base::TimeDelta::FromDays(1)); |
| 59 return row; |
| 60 } |
| 61 |
| 62 using StringPieces = std::vector<base::StringPiece>; |
| 63 |
| 64 StringPieces AllPrefixes(const std::string& str) { |
| 65 std::vector<base::StringPiece> res; |
| 66 res.reserve(str.size()); |
| 67 for (auto char_it = str.begin(); char_it != str.end(); ++char_it) |
| 68 res.push_back({str.begin(), char_it}); |
| 69 return res; |
| 70 } |
| 71 |
| 72 } // namespace |
| 73 |
| 74 class HQPPerfTestOnePopularURL : public testing::Test { |
| 75 protected: |
| 76 HQPPerfTestOnePopularURL() = default; |
| 77 |
| 78 void SetUp() override; |
| 79 void TearDown() override; |
| 80 |
| 81 // Populates history with variations of the same URL. |
| 82 void PrepareData(); |
| 83 |
| 84 // Runs HQP on a banch of consecutive pieces of an input string and times |
| 85 // them. Resulting timings printed in groups. |
| 86 template <typename PieceIt> |
| 87 void RunAllTests(PieceIt first, PieceIt last); |
| 88 |
| 89 // Encapsulates calls to performance infrastructure. |
| 90 void PrintMeasurements(const std::string& trace_name, |
| 91 const std::vector<base::TimeDelta>& measurements); |
| 92 |
| 93 history::HistoryBackend* history_backend() { |
| 94 return client_->GetHistoryService()->history_backend_.get(); |
| 95 } |
| 96 |
| 97 private: |
| 98 base::TimeDelta RunTest(const base::string16& text); |
| 99 |
| 100 base::MessageLoop message_loop_; |
| 101 std::unique_ptr<FakeAutocompleteProviderClient> client_; |
| 102 |
| 103 scoped_refptr<HistoryQuickProvider> provider_; |
| 104 |
| 105 DISALLOW_COPY_AND_ASSIGN(HQPPerfTestOnePopularURL); |
| 106 }; |
| 107 |
| 108 void HQPPerfTestOnePopularURL::SetUp() { |
| 109 if (base::ThreadTicks::IsSupported()) |
| 110 base::ThreadTicks::WaitUntilInitialized(); |
| 111 client_.reset(new FakeAutocompleteProviderClient()); |
| 112 ASSERT_TRUE(client_->GetHistoryService()); |
| 113 ASSERT_NO_FATAL_FAILURE(PrepareData()); |
| 114 } |
| 115 |
| 116 void HQPPerfTestOnePopularURL::TearDown() { |
| 117 provider_ = nullptr; |
| 118 // The InMemoryURLIndex must be explicitly shut down or it will DCHECK() in |
| 119 // its destructor. |
| 120 client_->GetInMemoryURLIndex()->Shutdown(); |
| 121 client_->set_in_memory_url_index(nullptr); |
| 122 // History index rebuild task is created from main thread during SetUp, |
| 123 // performed on DB thread and must be deleted on main thread. |
| 124 // Run main loop to process delete task, to prevent leaks. |
| 125 base::RunLoop().RunUntilIdle(); |
| 126 } |
| 127 |
| 128 void HQPPerfTestOnePopularURL::PrepareData() { |
| 129 // Adding fake urls to db must be done before RebuildFromHistory(). This will |
| 130 // ensure that the index is properly populated with data from the database. |
| 131 constexpr size_t kSimilarUrlCount = 10000; |
| 132 for (size_t i = 0; i < kSimilarUrlCount; ++i) |
| 133 AddFakeURLToHistoryDB(history_backend()->db(), GeneratePopularURLRow()); |
| 134 |
| 135 InMemoryURLIndex* url_index = client_->GetInMemoryURLIndex(); |
| 136 url_index->RebuildFromHistory( |
| 137 client_->GetHistoryService()->history_backend_->db()); |
| 138 BlockUntilInMemoryURLIndexIsRefreshed(url_index); |
| 139 |
| 140 // History index refresh creates rebuilt tasks to run on history thread. |
| 141 // Block here to make sure that all of them are complete. |
| 142 history::BlockUntilHistoryProcessesPendingRequests( |
| 143 client_->GetHistoryService()); |
| 144 |
| 145 provider_ = new HistoryQuickProvider(client_.get()); |
| 146 } |
| 147 |
| 148 void HQPPerfTestOnePopularURL::PrintMeasurements( |
| 149 const std::string& trace_name, |
| 150 const std::vector<base::TimeDelta>& measurements) { |
| 151 auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); |
| 152 |
| 153 std::string durations; |
| 154 for (const auto& measurement : measurements) |
| 155 durations += std::to_string(measurement.InMillisecondsRoundedUp()) + ','; |
| 156 |
| 157 perf_test::PrintResultList(test_info->test_case_name(), test_info->name(), |
| 158 trace_name, durations, "ms", true); |
| 159 } |
| 160 |
| 161 base::TimeDelta HQPPerfTestOnePopularURL::RunTest(const base::string16& text) { |
| 162 base::RunLoop().RunUntilIdle(); |
| 163 AutocompleteInput input(text, base::string16::npos, std::string(), GURL(), |
| 164 metrics::OmniboxEventProto::INVALID_SPEC, false, |
| 165 false, true, true, false, TestSchemeClassifier()); |
| 166 |
| 167 if (base::ThreadTicks::IsSupported()) { |
| 168 base::ThreadTicks start = base::ThreadTicks::Now(); |
| 169 provider_->Start(input, false); |
| 170 return base::ThreadTicks::Now() - start; |
| 171 } |
| 172 |
| 173 base::Time start = base::Time::Now(); |
| 174 provider_->Start(input, false); |
| 175 return base::Time::Now() - start; |
| 176 } |
| 177 |
| 178 template <typename PieceIt> |
| 179 void HQPPerfTestOnePopularURL::RunAllTests(PieceIt first, PieceIt last) { |
| 180 constexpr size_t kTestGroupSize = 5; |
| 181 std::vector<base::TimeDelta> measurements; |
| 182 measurements.reserve(kTestGroupSize); |
| 183 |
| 184 for (PieceIt group_start = first; group_start != last;) { |
| 185 PieceIt group_end = std::min(group_start + kTestGroupSize, last); |
| 186 |
| 187 std::transform(group_start, group_end, std::back_inserter(measurements), |
| 188 [this](const base::StringPiece& prefix) { |
| 189 return RunTest(base::UTF8ToUTF16(prefix)); |
| 190 }); |
| 191 |
| 192 PrintMeasurements(std::to_string(group_start->size()) + '-' + |
| 193 std::to_string((group_end - 1)->size()), |
| 194 measurements); |
| 195 |
| 196 measurements.clear(); |
| 197 group_start = group_end; |
| 198 } |
| 199 } |
| 200 |
| 201 TEST_F(HQPPerfTestOnePopularURL, Typing) { |
| 202 std::string test_url = GeneratePopularURLRow().url().spec(); |
| 203 StringPieces prefixes = AllPrefixes(test_url); |
| 204 RunAllTests(prefixes.begin(), prefixes.end()); |
| 205 } |
| 206 |
| 207 TEST_F(HQPPerfTestOnePopularURL, Backspacing) { |
| 208 std::string test_url = GeneratePopularURLRow().url().spec(); |
| 209 StringPieces prefixes = AllPrefixes(test_url); |
| 210 RunAllTests(prefixes.rbegin(), prefixes.rend()); |
| 211 } |
| 212 |
| 213 } // namespace history |
OLD | NEW |