Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / disk_cache / blockfile / disk_cache_perftest.cc
blob9aaa7f407b1aa62c049419154302adbcf6adf38a
1 // Copyright (c) 2011 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.
5 #include <string>
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/hash.h"
11 #include "base/strings/string_util.h"
12 #include "base/test/perf_time_logger.h"
13 #include "base/test/test_file_util.h"
14 #include "base/threading/thread.h"
15 #include "net/base/cache_type.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/disk_cache/blockfile/backend_impl.h"
20 #include "net/disk_cache/blockfile/block_files.h"
21 #include "net/disk_cache/disk_cache.h"
22 #include "net/disk_cache/disk_cache_test_base.h"
23 #include "net/disk_cache/disk_cache_test_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "testing/platform_test.h"
27 using base::Time;
29 namespace {
31 struct TestEntry {
32 std::string key;
33 int data_len;
35 typedef std::vector<TestEntry> TestEntries;
37 const int kMaxSize = 16 * 1024 - 1;
39 // Creates num_entries on the cache, and writes 200 bytes of metadata and up
40 // to kMaxSize of data to each entry.
41 bool TimeWrite(int num_entries, disk_cache::Backend* cache,
42 TestEntries* entries) {
43 const int kSize1 = 200;
44 scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1));
45 scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kMaxSize));
47 CacheTestFillBuffer(buffer1->data(), kSize1, false);
48 CacheTestFillBuffer(buffer2->data(), kMaxSize, false);
50 int expected = 0;
52 MessageLoopHelper helper;
53 CallbackTest callback(&helper, true);
55 base::PerfTimeLogger timer("Write disk cache entries");
57 for (int i = 0; i < num_entries; i++) {
58 TestEntry entry;
59 entry.key = GenerateKey(true);
60 entry.data_len = rand() % kMaxSize;
61 entries->push_back(entry);
63 disk_cache::Entry* cache_entry;
64 net::TestCompletionCallback cb;
65 int rv = cache->CreateEntry(entry.key, &cache_entry, cb.callback());
66 if (net::OK != cb.GetResult(rv))
67 break;
68 int ret = cache_entry->WriteData(
69 0, 0, buffer1.get(), kSize1,
70 base::Bind(&CallbackTest::Run, base::Unretained(&callback)), false);
71 if (net::ERR_IO_PENDING == ret)
72 expected++;
73 else if (kSize1 != ret)
74 break;
76 ret = cache_entry->WriteData(
77 1, 0, buffer2.get(), entry.data_len,
78 base::Bind(&CallbackTest::Run, base::Unretained(&callback)), false);
79 if (net::ERR_IO_PENDING == ret)
80 expected++;
81 else if (entry.data_len != ret)
82 break;
83 cache_entry->Close();
86 helper.WaitUntilCacheIoFinished(expected);
87 timer.Done();
89 return (expected == helper.callbacks_called());
92 // Reads the data and metadata from each entry listed on |entries|.
93 bool TimeRead(int num_entries, disk_cache::Backend* cache,
94 const TestEntries& entries, bool cold) {
95 const int kSize1 = 200;
96 scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1));
97 scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kMaxSize));
99 CacheTestFillBuffer(buffer1->data(), kSize1, false);
100 CacheTestFillBuffer(buffer2->data(), kMaxSize, false);
102 int expected = 0;
104 MessageLoopHelper helper;
105 CallbackTest callback(&helper, true);
107 const char* message = cold ? "Read disk cache entries (cold)" :
108 "Read disk cache entries (warm)";
109 base::PerfTimeLogger timer(message);
111 for (int i = 0; i < num_entries; i++) {
112 disk_cache::Entry* cache_entry;
113 net::TestCompletionCallback cb;
114 int rv = cache->OpenEntry(entries[i].key, &cache_entry, cb.callback());
115 if (net::OK != cb.GetResult(rv))
116 break;
117 int ret = cache_entry->ReadData(
118 0, 0, buffer1.get(), kSize1,
119 base::Bind(&CallbackTest::Run, base::Unretained(&callback)));
120 if (net::ERR_IO_PENDING == ret)
121 expected++;
122 else if (kSize1 != ret)
123 break;
125 ret = cache_entry->ReadData(
126 1, 0, buffer2.get(), entries[i].data_len,
127 base::Bind(&CallbackTest::Run, base::Unretained(&callback)));
128 if (net::ERR_IO_PENDING == ret)
129 expected++;
130 else if (entries[i].data_len != ret)
131 break;
132 cache_entry->Close();
135 helper.WaitUntilCacheIoFinished(expected);
136 timer.Done();
138 return (expected == helper.callbacks_called());
141 int BlockSize() {
142 // We can use form 1 to 4 blocks.
143 return (rand() & 0x3) + 1;
146 } // namespace
148 TEST_F(DiskCacheTest, Hash) {
149 int seed = static_cast<int>(Time::Now().ToInternalValue());
150 srand(seed);
152 base::PerfTimeLogger timer("Hash disk cache keys");
153 for (int i = 0; i < 300000; i++) {
154 std::string key = GenerateKey(true);
155 base::Hash(key);
157 timer.Done();
160 TEST_F(DiskCacheTest, CacheBackendPerformance) {
161 base::Thread cache_thread("CacheThread");
162 ASSERT_TRUE(cache_thread.StartWithOptions(
163 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
165 ASSERT_TRUE(CleanupCacheDir());
166 net::TestCompletionCallback cb;
167 scoped_ptr<disk_cache::Backend> cache;
168 int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
169 net::CACHE_BACKEND_BLOCKFILE,
170 cache_path_,
172 false,
173 cache_thread.task_runner(),
174 NULL,
175 &cache,
176 cb.callback());
178 ASSERT_EQ(net::OK, cb.GetResult(rv));
180 int seed = static_cast<int>(Time::Now().ToInternalValue());
181 srand(seed);
183 TestEntries entries;
184 int num_entries = 1000;
186 EXPECT_TRUE(TimeWrite(num_entries, cache.get(), &entries));
188 base::MessageLoop::current()->RunUntilIdle();
189 cache.reset();
191 ASSERT_TRUE(base::EvictFileFromSystemCache(
192 cache_path_.AppendASCII("index")));
193 ASSERT_TRUE(base::EvictFileFromSystemCache(
194 cache_path_.AppendASCII("data_0")));
195 ASSERT_TRUE(base::EvictFileFromSystemCache(
196 cache_path_.AppendASCII("data_1")));
197 ASSERT_TRUE(base::EvictFileFromSystemCache(
198 cache_path_.AppendASCII("data_2")));
199 ASSERT_TRUE(base::EvictFileFromSystemCache(
200 cache_path_.AppendASCII("data_3")));
202 rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
203 net::CACHE_BACKEND_BLOCKFILE,
204 cache_path_,
206 false,
207 cache_thread.task_runner(),
208 NULL,
209 &cache,
210 cb.callback());
211 ASSERT_EQ(net::OK, cb.GetResult(rv));
213 EXPECT_TRUE(TimeRead(num_entries, cache.get(), entries, true));
215 EXPECT_TRUE(TimeRead(num_entries, cache.get(), entries, false));
217 base::MessageLoop::current()->RunUntilIdle();
220 // Creating and deleting "entries" on a block-file is something quite frequent
221 // (after all, almost everything is stored on block files). The operation is
222 // almost free when the file is empty, but can be expensive if the file gets
223 // fragmented, or if we have multiple files. This test measures that scenario,
224 // by using multiple, highly fragmented files.
225 TEST_F(DiskCacheTest, BlockFilesPerformance) {
226 ASSERT_TRUE(CleanupCacheDir());
228 disk_cache::BlockFiles files(cache_path_);
229 ASSERT_TRUE(files.Init(true));
231 int seed = static_cast<int>(Time::Now().ToInternalValue());
232 srand(seed);
234 const int kNumEntries = 60000;
235 disk_cache::Addr* address = new disk_cache::Addr[kNumEntries];
237 base::PerfTimeLogger timer1("Fill three block-files");
239 // Fill up the 32-byte block file (use three files).
240 for (int i = 0; i < kNumEntries; i++) {
241 EXPECT_TRUE(files.CreateBlock(disk_cache::RANKINGS, BlockSize(),
242 &address[i]));
245 timer1.Done();
246 base::PerfTimeLogger timer2("Create and delete blocks");
248 for (int i = 0; i < 200000; i++) {
249 int entry = rand() * (kNumEntries / RAND_MAX + 1);
250 if (entry >= kNumEntries)
251 entry = 0;
253 files.DeleteBlock(address[entry], false);
254 EXPECT_TRUE(files.CreateBlock(disk_cache::RANKINGS, BlockSize(),
255 &address[entry]));
258 timer2.Done();
259 base::MessageLoop::current()->RunUntilIdle();
260 delete[] address;