OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits> | 5 #include <limits> |
6 #include <string> | 6 #include <string> |
7 | 7 |
| 8 #include "base/barrier_closure.h" |
8 #include "base/bind.h" | 9 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
10 #include "base/files/file_enumerator.h" | 11 #include "base/files/file_enumerator.h" |
11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
12 #include "base/hash.h" | 13 #include "base/hash.h" |
13 #include "base/process/process_metrics.h" | 14 #include "base/process/process_metrics.h" |
14 #include "base/rand_util.h" | 15 #include "base/rand_util.h" |
15 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
| 17 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
17 #include "base/test/perf_time_logger.h" | 19 #include "base/test/perf_time_logger.h" |
18 #include "base/test/test_file_util.h" | 20 #include "base/test/test_file_util.h" |
19 #include "base/threading/thread.h" | 21 #include "base/threading/thread.h" |
20 #include "net/base/cache_type.h" | 22 #include "net/base/cache_type.h" |
21 #include "net/base/io_buffer.h" | 23 #include "net/base/io_buffer.h" |
22 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
23 #include "net/base/test_completion_callback.h" | 25 #include "net/base/test_completion_callback.h" |
24 #include "net/disk_cache/blockfile/backend_impl.h" | 26 #include "net/disk_cache/blockfile/backend_impl.h" |
25 #include "net/disk_cache/blockfile/block_files.h" | 27 #include "net/disk_cache/blockfile/block_files.h" |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 | 302 |
301 files.DeleteBlock(address[entry], false); | 303 files.DeleteBlock(address[entry], false); |
302 EXPECT_TRUE( | 304 EXPECT_TRUE( |
303 files.CreateBlock(disk_cache::RANKINGS, block_size, &address[entry])); | 305 files.CreateBlock(disk_cache::RANKINGS, block_size, &address[entry])); |
304 } | 306 } |
305 | 307 |
306 timer2.Done(); | 308 timer2.Done(); |
307 base::RunLoop().RunUntilIdle(); | 309 base::RunLoop().RunUntilIdle(); |
308 } | 310 } |
309 | 311 |
| 312 void VerifyRvAndCallClosure(base::Closure* c, int expect_rv, int rv) { |
| 313 EXPECT_EQ(expect_rv, rv); |
| 314 c->Run(); |
| 315 } |
| 316 |
| 317 TEST_F(DiskCachePerfTest, SimpleCacheInitialReadPortion) { |
| 318 // A benchmark that aims to measure how much time we take in I/O thread |
| 319 // for initial bookkeeping before returning to the caller, and how much |
| 320 // after (batched up some). The later portion includes some event loop |
| 321 // overhead. |
| 322 const int kBatchSize = 100; |
| 323 |
| 324 SetSimpleCacheMode(); |
| 325 |
| 326 InitCache(); |
| 327 // Write out the entries, and keep their objects around. |
| 328 scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kHeadersSize)); |
| 329 scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kBodySize)); |
| 330 |
| 331 CacheTestFillBuffer(buffer1->data(), kHeadersSize, false); |
| 332 CacheTestFillBuffer(buffer2->data(), kBodySize, false); |
| 333 |
| 334 disk_cache::Entry* cache_entry[kBatchSize]; |
| 335 for (int i = 0; i < kBatchSize; ++i) { |
| 336 net::TestCompletionCallback cb; |
| 337 int rv = cache_->CreateEntry(base::IntToString(i), &cache_entry[i], |
| 338 cb.callback()); |
| 339 ASSERT_EQ(net::OK, cb.GetResult(rv)); |
| 340 |
| 341 rv = cache_entry[i]->WriteData(0, 0, buffer1.get(), kHeadersSize, |
| 342 cb.callback(), false); |
| 343 ASSERT_EQ(kHeadersSize, cb.GetResult(rv)); |
| 344 rv = cache_entry[i]->WriteData(1, 0, buffer2.get(), kBodySize, |
| 345 cb.callback(), false); |
| 346 ASSERT_EQ(kBodySize, cb.GetResult(rv)); |
| 347 } |
| 348 |
| 349 // Now repeatedly read these, batching up the waiting to try to |
| 350 // account for the two portions separately. Note that we need separate entries |
| 351 // since we are trying to keep interesting work from being on the delayed-done |
| 352 // portion. |
| 353 const int kIterations = 50000; |
| 354 |
| 355 double elapsed_early = 0.0; |
| 356 double elapsed_late = 0.0; |
| 357 |
| 358 for (int i = 0; i < kIterations; ++i) { |
| 359 int expected = 0; |
| 360 |
| 361 base::RunLoop event_loop; |
| 362 base::Closure barrier = |
| 363 base::BarrierClosure(kIterations, event_loop.QuitWhenIdleClosure()); |
| 364 net::CompletionCallback cb_batch(base::Bind( |
| 365 VerifyRvAndCallClosure, base::Unretained(&barrier), kHeadersSize)); |
| 366 |
| 367 base::ElapsedTimer timer_early; |
| 368 for (int e = 0; e < kBatchSize; ++e) { |
| 369 int rv = |
| 370 cache_entry[e]->ReadData(0, 0, buffer1.get(), kHeadersSize, cb_batch); |
| 371 if (rv == net::ERR_IO_PENDING) |
| 372 ++expected; |
| 373 else |
| 374 ASSERT_EQ(kHeadersSize, rv); |
| 375 } |
| 376 elapsed_early += timer_early.Elapsed().InMillisecondsF(); |
| 377 |
| 378 base::ElapsedTimer timer_late; |
| 379 |
| 380 if (expected != 0) { |
| 381 // if expected is x, done will only get called x times, not kIterations |
| 382 // times. This is a bill silly, but just fake the other kIterations - x |
| 383 // calls. This is a bit silly, but unlike MessageLoopHelper, it doesn't do |
| 384 // major sleeps. |
| 385 for (int extra = 0; extra < kIterations - expected; ++extra) |
| 386 barrier.Run(); |
| 387 |
| 388 event_loop.Run(); |
| 389 } |
| 390 |
| 391 elapsed_late += timer_late.Elapsed().InMillisecondsF(); |
| 392 } |
| 393 |
| 394 // Cleanup |
| 395 for (int i = 0; i < kBatchSize; ++i) |
| 396 cache_entry[i]->Close(); |
| 397 |
| 398 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); |
| 399 base::RunLoop().RunUntilIdle(); |
| 400 LOG(ERROR) << "Early portion:" << elapsed_early << " ms"; |
| 401 LOG(ERROR) << "\tPer entry:" |
| 402 << 1000 * (elapsed_early / (kIterations * kBatchSize)) << " us"; |
| 403 LOG(ERROR) << "Event loop portion: " << elapsed_late << " ms"; |
| 404 LOG(ERROR) << "\tPer entry:" |
| 405 << 1000 * (elapsed_late / (kIterations * kBatchSize)) << " us"; |
| 406 } |
| 407 |
310 // Measures how quickly SimpleIndex can compute which entries to evict. | 408 // Measures how quickly SimpleIndex can compute which entries to evict. |
311 TEST(SimpleIndexPerfTest, EvictionPerformance) { | 409 TEST(SimpleIndexPerfTest, EvictionPerformance) { |
312 const int kEntries = 10000; | 410 const int kEntries = 10000; |
313 | 411 |
314 class NoOpDelegate : public disk_cache::SimpleIndexDelegate { | 412 class NoOpDelegate : public disk_cache::SimpleIndexDelegate { |
315 void DoomEntries(std::vector<uint64_t>* entry_hashes, | 413 void DoomEntries(std::vector<uint64_t>* entry_hashes, |
316 const net::CompletionCallback& callback) override {} | 414 const net::CompletionCallback& callback) override {} |
317 }; | 415 }; |
318 | 416 |
319 NoOpDelegate delegate; | 417 NoOpDelegate delegate; |
(...skipping 19 matching lines...) Expand all Loading... |
339 index.SetMaxSize(kEntries); | 437 index.SetMaxSize(kEntries); |
340 index.UpdateEntrySize(0, 1u); | 438 index.UpdateEntrySize(0, 1u); |
341 evict_elapsed_ms += timer.Elapsed().InMillisecondsF(); | 439 evict_elapsed_ms += timer.Elapsed().InMillisecondsF(); |
342 } | 440 } |
343 | 441 |
344 LOG(ERROR) << "Average time to evict:" << (evict_elapsed_ms / iterations) | 442 LOG(ERROR) << "Average time to evict:" << (evict_elapsed_ms / iterations) |
345 << "ms"; | 443 << "ms"; |
346 } | 444 } |
347 | 445 |
348 } // namespace | 446 } // namespace |
OLD | NEW |