xref: /aosp_15_r20/external/cronet/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 "net/extras/sqlite/sqlite_persistent_cookie_store.h"
6 
7 #include <vector>
8 
9 #include "base/compiler_specific.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/functional/bind.h"
12 #include "base/rand_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/task/sequenced_task_runner.h"
16 #include "base/task/thread_pool.h"
17 #include "base/test/task_environment.h"
18 #include "base/time/time.h"
19 #include "base/timer/elapsed_timer.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/cookies/canonical_cookie.h"
22 #include "net/cookies/cookie_constants.h"
23 #include "net/extras/sqlite/cookie_crypto_delegate.h"
24 #include "net/log/net_log_with_source.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/perf/perf_result_reporter.h"
27 #include "url/gurl.h"
28 
29 namespace net {
30 
31 namespace {
32 
33 const base::FilePath::CharType cookie_filename[] = FILE_PATH_LITERAL("Cookies");
34 
35 static const int kNumDomains = 300;
36 static const int kCookiesPerDomain = 50;
37 
38 // Prime number noticeably larger than kNumDomains or kCookiesPerDomain
39 // so that multiplying this number by an incrementing index and moduloing
40 // with those values will return semi-random results.
41 static const int kRandomSeed = 13093;
42 static_assert(kRandomSeed > 10 * kNumDomains,
43               "kRandomSeed not high enough for number of domains");
44 static_assert(kRandomSeed > 10 * kCookiesPerDomain,
45               "kRandomSeed not high enough for number of cookies per domain");
46 
47 static constexpr char kMetricPrefixSQLPCS[] = "SQLitePersistentCookieStore.";
48 static constexpr char kMetricOperationDurationMs[] = "operation_duration";
49 
SetUpSQLPCSReporter(const std::string & story)50 perf_test::PerfResultReporter SetUpSQLPCSReporter(const std::string& story) {
51   perf_test::PerfResultReporter reporter(kMetricPrefixSQLPCS, story);
52   reporter.RegisterImportantMetric(kMetricOperationDurationMs, "ms");
53   return reporter;
54 }
55 
56 }  // namespace
57 
58 class SQLitePersistentCookieStorePerfTest : public testing::Test {
59  public:
SQLitePersistentCookieStorePerfTest()60   SQLitePersistentCookieStorePerfTest()
61       : test_start_(base::Time::Now()),
62         loaded_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
63                       base::WaitableEvent::InitialState::NOT_SIGNALED),
64         key_loaded_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
65                           base::WaitableEvent::InitialState::NOT_SIGNALED) {}
66 
OnLoaded(std::vector<std::unique_ptr<CanonicalCookie>> cookies)67   void OnLoaded(std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
68     cookies_.swap(cookies);
69     loaded_event_.Signal();
70   }
71 
OnKeyLoaded(std::vector<std::unique_ptr<CanonicalCookie>> cookies)72   void OnKeyLoaded(std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
73     cookies_.swap(cookies);
74     key_loaded_event_.Signal();
75   }
76 
Load()77   void Load() {
78     store_->Load(base::BindOnce(&SQLitePersistentCookieStorePerfTest::OnLoaded,
79                                 base::Unretained(this)),
80                  NetLogWithSource());
81     loaded_event_.Wait();
82   }
83 
CookieFromIndices(int domain_num,int cookie_num)84   CanonicalCookie CookieFromIndices(int domain_num, int cookie_num) {
85     base::Time t(
86         test_start_ +
87         base::Microseconds(domain_num * kCookiesPerDomain + cookie_num));
88     std::string domain_name(base::StringPrintf(".domain_%d.com", domain_num));
89     return *CanonicalCookie::CreateUnsafeCookieForTesting(
90         base::StringPrintf("Cookie_%d", cookie_num), "1", domain_name, "/", t,
91         t, t, t, false, false, CookieSameSite::NO_RESTRICTION,
92         COOKIE_PRIORITY_DEFAULT);
93   }
94 
SetUp()95   void SetUp() override {
96     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
97     store_ = base::MakeRefCounted<SQLitePersistentCookieStore>(
98         temp_dir_.GetPath().Append(cookie_filename), client_task_runner_,
99         background_task_runner_, /*restore_old_session_cookies=*/true,
100         /*crypto_delegate=*/nullptr, /*enable_exclusive_access=*/false);
101     std::vector<CanonicalCookie*> cookies;
102     Load();
103     ASSERT_EQ(0u, cookies_.size());
104     // Creates kNumDomains*kCookiesPerDomain cookies from kNumDomains eTLD+1s.
105     for (int domain_num = 0; domain_num < kNumDomains; domain_num++) {
106       for (int cookie_num = 0; cookie_num < kCookiesPerDomain; ++cookie_num) {
107         store_->AddCookie(CookieFromIndices(domain_num, cookie_num));
108       }
109     }
110     // Replace the store effectively destroying the current one and forcing it
111     // to write its data to disk.
112     store_ = nullptr;
113 
114     // Flush ThreadPool tasks, causing pending commits to run.
115     task_environment_.RunUntilIdle();
116 
117     store_ = base::MakeRefCounted<SQLitePersistentCookieStore>(
118         temp_dir_.GetPath().Append(cookie_filename), client_task_runner_,
119         background_task_runner_, /*restore_old_session_cookies=*/true,
120         /*crypto_delegate=*/nullptr, /*enable_exclusive_access=*/false);
121   }
122 
123   // Pick a random cookie out of the 15000 in the store and return it.
124   // Note that this distribution is intended to be random for purposes of
125   // probing, but will be the same each time the test is run for
126   // reproducibility of performance.
RandomCookie()127   CanonicalCookie RandomCookie() {
128     int consistent_random_value = ++seed_multiple_ * kRandomSeed;
129     int domain = consistent_random_value % kNumDomains;
130     int cookie_num = consistent_random_value % kCookiesPerDomain;
131     return CookieFromIndices(domain, cookie_num);
132   }
133 
TearDown()134   void TearDown() override { store_ = nullptr; }
135 
StartPerfMeasurement()136   void StartPerfMeasurement() {
137     DCHECK(perf_measurement_start_.is_null());
138     perf_measurement_start_ = base::Time::Now();
139   }
140 
EndPerfMeasurement(const std::string & story)141   void EndPerfMeasurement(const std::string& story) {
142     DCHECK(!perf_measurement_start_.is_null());
143     base::TimeDelta elapsed = base::Time::Now() - perf_measurement_start_;
144     perf_measurement_start_ = base::Time();
145     auto reporter = SetUpSQLPCSReporter(story);
146     reporter.AddResult(kMetricOperationDurationMs, elapsed.InMillisecondsF());
147   }
148 
149  protected:
150   int seed_multiple_ = 1;
151   base::Time test_start_;
152   base::test::TaskEnvironment task_environment_;
153   const scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
154       base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
155   const scoped_refptr<base::SequencedTaskRunner> client_task_runner_ =
156       base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
157   base::WaitableEvent loaded_event_;
158   base::WaitableEvent key_loaded_event_;
159   std::vector<std::unique_ptr<CanonicalCookie>> cookies_;
160   base::ScopedTempDir temp_dir_;
161   scoped_refptr<SQLitePersistentCookieStore> store_;
162   base::Time perf_measurement_start_;
163 };
164 
165 // Test the performance of priority load of cookies for a specific domain key
TEST_F(SQLitePersistentCookieStorePerfTest,TestLoadForKeyPerformance)166 TEST_F(SQLitePersistentCookieStorePerfTest, TestLoadForKeyPerformance) {
167   ASSERT_LT(3, kNumDomains);
168   for (int domain_num = 0; domain_num < 3; ++domain_num) {
169     std::string domain_name(base::StringPrintf("domain_%d.com", domain_num));
170     StartPerfMeasurement();
171     store_->LoadCookiesForKey(
172         domain_name,
173         base::BindOnce(&SQLitePersistentCookieStorePerfTest::OnKeyLoaded,
174                        base::Unretained(this)));
175     key_loaded_event_.Wait();
176     EndPerfMeasurement("load_for_key");
177 
178     ASSERT_EQ(50U, cookies_.size());
179   }
180 }
181 
182 // Test the performance of load
TEST_F(SQLitePersistentCookieStorePerfTest,TestLoadPerformance)183 TEST_F(SQLitePersistentCookieStorePerfTest, TestLoadPerformance) {
184   StartPerfMeasurement();
185   Load();
186   EndPerfMeasurement("load");
187 
188   ASSERT_EQ(kNumDomains * kCookiesPerDomain, static_cast<int>(cookies_.size()));
189 }
190 
191 // Test deletion performance.
TEST_F(SQLitePersistentCookieStorePerfTest,TestDeletePerformance)192 TEST_F(SQLitePersistentCookieStorePerfTest, TestDeletePerformance) {
193   const int kNumToDelete = 50;
194   const int kNumIterations = 400;
195 
196   // Figure out the kNumToDelete cookies.
197   std::vector<CanonicalCookie> cookies;
198   cookies.reserve(kNumToDelete);
199   for (int cookie = 0; cookie < kNumToDelete; ++cookie) {
200     cookies.push_back(RandomCookie());
201   }
202   ASSERT_EQ(static_cast<size_t>(kNumToDelete), cookies.size());
203 
204   StartPerfMeasurement();
205   for (int i = 0; i < kNumIterations; ++i) {
206     // Delete and flush
207     for (int cookie = 0; cookie < kNumToDelete; ++cookie) {
208       store_->DeleteCookie(cookies[cookie]);
209     }
210     {
211       TestClosure test_closure;
212       store_->Flush(test_closure.closure());
213       test_closure.WaitForResult();
214     }
215 
216     // Add and flush
217     for (int cookie = 0; cookie < kNumToDelete; ++cookie) {
218       store_->AddCookie(cookies[cookie]);
219     }
220 
221     TestClosure test_closure;
222     store_->Flush(test_closure.closure());
223     test_closure.WaitForResult();
224   }
225   EndPerfMeasurement("delete");
226 }
227 
228 // Test update performance.
TEST_F(SQLitePersistentCookieStorePerfTest,TestUpdatePerformance)229 TEST_F(SQLitePersistentCookieStorePerfTest, TestUpdatePerformance) {
230   const int kNumToUpdate = 50;
231   const int kNumIterations = 400;
232 
233   // Figure out the kNumToUpdate cookies.
234   std::vector<CanonicalCookie> cookies;
235   cookies.reserve(kNumToUpdate);
236   for (int cookie = 0; cookie < kNumToUpdate; ++cookie) {
237     cookies.push_back(RandomCookie());
238   }
239   ASSERT_EQ(static_cast<size_t>(kNumToUpdate), cookies.size());
240 
241   StartPerfMeasurement();
242   for (int i = 0; i < kNumIterations; ++i) {
243     // Update and flush
244     for (int cookie = 0; cookie < kNumToUpdate; ++cookie) {
245       store_->UpdateCookieAccessTime(cookies[cookie]);
246     }
247 
248     TestClosure test_closure;
249     store_->Flush(test_closure.closure());
250     test_closure.WaitForResult();
251   }
252   EndPerfMeasurement("update");
253 }
254 
255 }  // namespace net
256