Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / disk_cache / blockfile / disk_cache_perftest.cc
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.
4
5 #include <string>
6
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"
26
27 using base::Time;
28
29 namespace {
30
31 struct TestEntry {
32   std::string key;
33   int data_len;
34 };
35 typedef std::vector<TestEntry> TestEntries;
36
37 const int kMaxSize = 16 * 1024 - 1;
38
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));
46
47   CacheTestFillBuffer(buffer1->data(), kSize1, false);
48   CacheTestFillBuffer(buffer2->data(), kMaxSize, false);
49
50   int expected = 0;
51
52   MessageLoopHelper helper;
53   CallbackTest callback(&helper, true);
54
55   base::PerfTimeLogger timer("Write disk cache entries");
56
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);
62
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;
75
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();
84   }
85
86   helper.WaitUntilCacheIoFinished(expected);
87   timer.Done();
88
89   return (expected == helper.callbacks_called());
90 }
91
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));
98
99   CacheTestFillBuffer(buffer1->data(), kSize1, false);
100   CacheTestFillBuffer(buffer2->data(), kMaxSize, false);
101
102   int expected = 0;
103
104   MessageLoopHelper helper;
105   CallbackTest callback(&helper, true);
106
107   const char* message = cold ? "Read disk cache entries (cold)" :
108                         "Read disk cache entries (warm)";
109   base::PerfTimeLogger timer(message);
110
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;
124
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();
133   }
134
135   helper.WaitUntilCacheIoFinished(expected);
136   timer.Done();
137
138   return (expected == helper.callbacks_called());
139 }
140
141 int BlockSize() {
142   // We can use form 1 to 4 blocks.
143   return (rand() & 0x3) + 1;
144 }
145
146 }  // namespace
147
148 TEST_F(DiskCacheTest, Hash) {
149   int seed = static_cast<int>(Time::Now().ToInternalValue());
150   srand(seed);
151
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);
156   }
157   timer.Done();
158 }
159
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)));
164
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_,
171                                           0,
172                                           false,
173                                           cache_thread.task_runner(),
174                                           NULL,
175                                           &cache,
176                                           cb.callback());
177
178   ASSERT_EQ(net::OK, cb.GetResult(rv));
179
180   int seed = static_cast<int>(Time::Now().ToInternalValue());
181   srand(seed);
182
183   TestEntries entries;
184   int num_entries = 1000;
185
186   EXPECT_TRUE(TimeWrite(num_entries, cache.get(), &entries));
187
188   base::MessageLoop::current()->RunUntilIdle();
189   cache.reset();
190
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")));
201
202   rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
203                                       net::CACHE_BACKEND_BLOCKFILE,
204                                       cache_path_,
205                                       0,
206                                       false,
207                                       cache_thread.task_runner(),
208                                       NULL,
209                                       &cache,
210                                       cb.callback());
211   ASSERT_EQ(net::OK, cb.GetResult(rv));
212
213   EXPECT_TRUE(TimeRead(num_entries, cache.get(), entries, true));
214
215   EXPECT_TRUE(TimeRead(num_entries, cache.get(), entries, false));
216
217   base::MessageLoop::current()->RunUntilIdle();
218 }
219
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());
227
228   disk_cache::BlockFiles files(cache_path_);
229   ASSERT_TRUE(files.Init(true));
230
231   int seed = static_cast<int>(Time::Now().ToInternalValue());
232   srand(seed);
233
234   const int kNumEntries = 60000;
235   disk_cache::Addr* address = new disk_cache::Addr[kNumEntries];
236
237   base::PerfTimeLogger timer1("Fill three block-files");
238
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]));
243   }
244
245   timer1.Done();
246   base::PerfTimeLogger timer2("Create and delete blocks");
247
248   for (int i = 0; i < 200000; i++) {
249     int entry = rand() * (kNumEntries / RAND_MAX + 1);
250     if (entry >= kNumEntries)
251       entry = 0;
252
253     files.DeleteBlock(address[entry], false);
254     EXPECT_TRUE(files.CreateBlock(disk_cache::RANKINGS, BlockSize(),
255                                   &address[entry]));
256   }
257
258   timer2.Done();
259   base::MessageLoop::current()->RunUntilIdle();
260   delete[] address;
261 }