123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709 |
- // Copyright (c) 2011 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <limits>
- #include <memory>
- #include <string>
- #include "base/barrier_closure.h"
- #include "base/bind.h"
- #include "base/files/file_enumerator.h"
- #include "base/files/file_path.h"
- #include "base/hash/hash.h"
- #include "base/memory/raw_ptr.h"
- #include "base/process/process_metrics.h"
- #include "base/rand_util.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_util.h"
- #include "base/test/scoped_run_loop_timeout.h"
- #include "base/test/test_file_util.h"
- #include "base/test/test_timeouts.h"
- #include "base/threading/thread.h"
- #include "base/time/time.h"
- #include "base/timer/elapsed_timer.h"
- #include "build/build_config.h"
- #include "net/base/cache_type.h"
- #include "net/base/completion_repeating_callback.h"
- #include "net/base/io_buffer.h"
- #include "net/base/net_errors.h"
- #include "net/base/test_completion_callback.h"
- #include "net/disk_cache/backend_cleanup_tracker.h"
- #include "net/disk_cache/blockfile/backend_impl.h"
- #include "net/disk_cache/blockfile/block_files.h"
- #include "net/disk_cache/disk_cache.h"
- #include "net/disk_cache/disk_cache_test_base.h"
- #include "net/disk_cache/disk_cache_test_util.h"
- #include "net/disk_cache/simple/simple_backend_impl.h"
- #include "net/disk_cache/simple/simple_index.h"
- #include "net/disk_cache/simple/simple_index_file.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/perf/perf_result_reporter.h"
- #include "testing/platform_test.h"
- using base::Time;
- namespace {
- const size_t kNumEntries = 10000;
- const int kHeadersSize = 2000;
- const int kBodySize = 72 * 1024 - 1;
- // HttpCache likes this chunk size.
- const int kChunkSize = 32 * 1024;
- // As of 2017-01-12, this is a typical per-tab limit on HTTP connections.
- const int kMaxParallelOperations = 10;
- static constexpr char kMetricPrefixDiskCache[] = "DiskCache.";
- static constexpr char kMetricPrefixSimpleIndex[] = "SimpleIndex.";
- static constexpr char kMetricCacheEntriesWriteTimeMs[] =
- "cache_entries_write_time";
- static constexpr char kMetricCacheHeadersReadTimeColdMs[] =
- "cache_headers_read_time_cold";
- static constexpr char kMetricCacheHeadersReadTimeWarmMs[] =
- "cache_headers_read_time_warm";
- static constexpr char kMetricCacheEntriesReadTimeColdMs[] =
- "cache_entries_read_time_cold";
- static constexpr char kMetricCacheEntriesReadTimeWarmMs[] =
- "cache_entries_read_time_warm";
- static constexpr char kMetricCacheKeysHashTimeMs[] = "cache_keys_hash_time";
- static constexpr char kMetricFillBlocksTimeMs[] = "fill_sequential_blocks_time";
- static constexpr char kMetricCreateDeleteBlocksTimeMs[] =
- "create_and_delete_random_blocks_time";
- static constexpr char kMetricSimpleCacheInitTotalTimeMs[] =
- "simple_cache_initial_read_total_time";
- static constexpr char kMetricSimpleCacheInitPerEntryTimeUs[] =
- "simple_cache_initial_read_per_entry_time";
- static constexpr char kMetricAverageEvictionTimeMs[] = "average_eviction_time";
- perf_test::PerfResultReporter SetUpDiskCacheReporter(const std::string& story) {
- perf_test::PerfResultReporter reporter(kMetricPrefixDiskCache, story);
- reporter.RegisterImportantMetric(kMetricCacheEntriesWriteTimeMs, "ms");
- reporter.RegisterImportantMetric(kMetricCacheHeadersReadTimeColdMs, "ms");
- reporter.RegisterImportantMetric(kMetricCacheHeadersReadTimeWarmMs, "ms");
- reporter.RegisterImportantMetric(kMetricCacheEntriesReadTimeColdMs, "ms");
- reporter.RegisterImportantMetric(kMetricCacheEntriesReadTimeWarmMs, "ms");
- reporter.RegisterImportantMetric(kMetricCacheKeysHashTimeMs, "ms");
- reporter.RegisterImportantMetric(kMetricFillBlocksTimeMs, "ms");
- reporter.RegisterImportantMetric(kMetricCreateDeleteBlocksTimeMs, "ms");
- reporter.RegisterImportantMetric(kMetricSimpleCacheInitTotalTimeMs, "ms");
- reporter.RegisterImportantMetric(kMetricSimpleCacheInitPerEntryTimeUs, "us");
- return reporter;
- }
- perf_test::PerfResultReporter SetUpSimpleIndexReporter(
- const std::string& story) {
- perf_test::PerfResultReporter reporter(kMetricPrefixSimpleIndex, story);
- reporter.RegisterImportantMetric(kMetricAverageEvictionTimeMs, "ms");
- return reporter;
- }
- void MaybeIncreaseFdLimitTo(unsigned int max_descriptors) {
- #if BUILDFLAG(IS_POSIX)
- base::IncreaseFdLimitTo(max_descriptors);
- #endif
- }
- struct TestEntry {
- std::string key;
- int data_len;
- };
- enum class WhatToRead {
- HEADERS_ONLY,
- HEADERS_AND_BODY,
- };
- class DiskCachePerfTest : public DiskCacheTestWithCache {
- public:
- DiskCachePerfTest() { MaybeIncreaseFdLimitTo(kFdLimitForCacheTests); }
- const std::vector<TestEntry>& entries() const { return entries_; }
- protected:
- // Helper methods for constructing tests.
- bool TimeWrites(const std::string& story);
- bool TimeReads(WhatToRead what_to_read,
- const std::string& metric,
- const std::string& story);
- void ResetAndEvictSystemDiskCache();
- // Callbacks used within tests for intermediate operations.
- void WriteCallback(net::CompletionOnceCallback final_callback,
- scoped_refptr<net::IOBuffer> headers_buffer,
- scoped_refptr<net::IOBuffer> body_buffer,
- disk_cache::Entry* cache_entry,
- int entry_index,
- size_t write_offset,
- int result);
- // Complete perf tests.
- void CacheBackendPerformance(const std::string& story);
- const size_t kFdLimitForCacheTests = 8192;
- std::vector<TestEntry> entries_;
- };
- class WriteHandler {
- public:
- WriteHandler(const DiskCachePerfTest* test,
- disk_cache::Backend* cache,
- net::CompletionOnceCallback final_callback)
- : test_(test), cache_(cache), final_callback_(std::move(final_callback)) {
- CacheTestFillBuffer(headers_buffer_->data(), kHeadersSize, false);
- CacheTestFillBuffer(body_buffer_->data(), kChunkSize, false);
- }
- void Run();
- protected:
- void CreateNextEntry();
- void CreateCallback(int data_len, disk_cache::EntryResult result);
- void WriteDataCallback(disk_cache::Entry* entry,
- int next_offset,
- int data_len,
- int expected_result,
- int result);
- private:
- bool CheckForErrorAndCancel(int result);
- raw_ptr<const DiskCachePerfTest> test_;
- raw_ptr<disk_cache::Backend> cache_;
- net::CompletionOnceCallback final_callback_;
- size_t next_entry_index_ = 0;
- size_t pending_operations_count_ = 0;
- int pending_result_ = net::OK;
- scoped_refptr<net::IOBuffer> headers_buffer_ =
- base::MakeRefCounted<net::IOBuffer>(kHeadersSize);
- scoped_refptr<net::IOBuffer> body_buffer_ =
- base::MakeRefCounted<net::IOBuffer>(kChunkSize);
- };
- void WriteHandler::Run() {
- for (int i = 0; i < kMaxParallelOperations; ++i) {
- ++pending_operations_count_;
- CreateNextEntry();
- }
- }
- void WriteHandler::CreateNextEntry() {
- ASSERT_GT(kNumEntries, next_entry_index_);
- TestEntry test_entry = test_->entries()[next_entry_index_++];
- auto callback =
- base::BindRepeating(&WriteHandler::CreateCallback, base::Unretained(this),
- test_entry.data_len);
- disk_cache::EntryResult result =
- cache_->CreateEntry(test_entry.key, net::HIGHEST, callback);
- if (result.net_error() != net::ERR_IO_PENDING)
- callback.Run(std::move(result));
- }
- void WriteHandler::CreateCallback(int data_len,
- disk_cache::EntryResult result) {
- if (CheckForErrorAndCancel(result.net_error()))
- return;
- disk_cache::Entry* entry = result.ReleaseEntry();
- net::CompletionRepeatingCallback callback = base::BindRepeating(
- &WriteHandler::WriteDataCallback, base::Unretained(this), entry, 0,
- data_len, kHeadersSize);
- int new_result = entry->WriteData(0, 0, headers_buffer_.get(), kHeadersSize,
- callback, false);
- if (new_result != net::ERR_IO_PENDING)
- callback.Run(new_result);
- }
- void WriteHandler::WriteDataCallback(disk_cache::Entry* entry,
- int next_offset,
- int data_len,
- int expected_result,
- int result) {
- if (CheckForErrorAndCancel(result)) {
- entry->Close();
- return;
- }
- DCHECK_LE(next_offset, data_len);
- if (next_offset == data_len) {
- entry->Close();
- if (next_entry_index_ < kNumEntries) {
- CreateNextEntry();
- } else {
- --pending_operations_count_;
- if (pending_operations_count_ == 0)
- std::move(final_callback_).Run(net::OK);
- }
- return;
- }
- int write_size = std::min(kChunkSize, data_len - next_offset);
- net::CompletionRepeatingCallback callback = base::BindRepeating(
- &WriteHandler::WriteDataCallback, base::Unretained(this), entry,
- next_offset + write_size, data_len, write_size);
- int new_result = entry->WriteData(1, next_offset, body_buffer_.get(),
- write_size, callback, true);
- if (new_result != net::ERR_IO_PENDING)
- callback.Run(new_result);
- }
- bool WriteHandler::CheckForErrorAndCancel(int result) {
- DCHECK_NE(net::ERR_IO_PENDING, result);
- if (result != net::OK && !(result > 0))
- pending_result_ = result;
- if (pending_result_ != net::OK) {
- --pending_operations_count_;
- if (pending_operations_count_ == 0)
- std::move(final_callback_).Run(pending_result_);
- return true;
- }
- return false;
- }
- class ReadHandler {
- public:
- ReadHandler(const DiskCachePerfTest* test,
- WhatToRead what_to_read,
- disk_cache::Backend* cache,
- net::CompletionOnceCallback final_callback)
- : test_(test),
- what_to_read_(what_to_read),
- cache_(cache),
- final_callback_(std::move(final_callback)) {
- for (auto& read_buffer : read_buffers_) {
- read_buffer = base::MakeRefCounted<net::IOBuffer>(
- std::max(kHeadersSize, kChunkSize));
- }
- }
- void Run();
- protected:
- void OpenNextEntry(int parallel_operation_index);
- void OpenCallback(int parallel_operation_index,
- int data_len,
- disk_cache::EntryResult result);
- void ReadDataCallback(int parallel_operation_index,
- disk_cache::Entry* entry,
- int next_offset,
- int data_len,
- int expected_result,
- int result);
- private:
- bool CheckForErrorAndCancel(int result);
- raw_ptr<const DiskCachePerfTest> test_;
- const WhatToRead what_to_read_;
- raw_ptr<disk_cache::Backend> cache_;
- net::CompletionOnceCallback final_callback_;
- size_t next_entry_index_ = 0;
- size_t pending_operations_count_ = 0;
- int pending_result_ = net::OK;
- scoped_refptr<net::IOBuffer> read_buffers_[kMaxParallelOperations];
- };
- void ReadHandler::Run() {
- for (int i = 0; i < kMaxParallelOperations; ++i) {
- OpenNextEntry(pending_operations_count_);
- ++pending_operations_count_;
- }
- }
- void ReadHandler::OpenNextEntry(int parallel_operation_index) {
- ASSERT_GT(kNumEntries, next_entry_index_);
- TestEntry test_entry = test_->entries()[next_entry_index_++];
- auto callback =
- base::BindRepeating(&ReadHandler::OpenCallback, base::Unretained(this),
- parallel_operation_index, test_entry.data_len);
- disk_cache::EntryResult result =
- cache_->OpenEntry(test_entry.key, net::HIGHEST, callback);
- if (result.net_error() != net::ERR_IO_PENDING)
- callback.Run(std::move(result));
- }
- void ReadHandler::OpenCallback(int parallel_operation_index,
- int data_len,
- disk_cache::EntryResult result) {
- if (CheckForErrorAndCancel(result.net_error()))
- return;
- disk_cache::Entry* entry = result.ReleaseEntry();
- EXPECT_EQ(data_len, entry->GetDataSize(1));
- net::CompletionRepeatingCallback callback = base::BindRepeating(
- &ReadHandler::ReadDataCallback, base::Unretained(this),
- parallel_operation_index, entry, 0, data_len, kHeadersSize);
- int new_result =
- entry->ReadData(0, 0, read_buffers_[parallel_operation_index].get(),
- kChunkSize, callback);
- if (new_result != net::ERR_IO_PENDING)
- callback.Run(new_result);
- }
- void ReadHandler::ReadDataCallback(int parallel_operation_index,
- disk_cache::Entry* entry,
- int next_offset,
- int data_len,
- int expected_result,
- int result) {
- if (CheckForErrorAndCancel(result)) {
- entry->Close();
- return;
- }
- DCHECK_LE(next_offset, data_len);
- if (what_to_read_ == WhatToRead::HEADERS_ONLY || next_offset == data_len) {
- entry->Close();
- if (next_entry_index_ < kNumEntries) {
- OpenNextEntry(parallel_operation_index);
- } else {
- --pending_operations_count_;
- if (pending_operations_count_ == 0)
- std::move(final_callback_).Run(net::OK);
- }
- return;
- }
- int expected_read_size = std::min(kChunkSize, data_len - next_offset);
- net::CompletionRepeatingCallback callback = base::BindRepeating(
- &ReadHandler::ReadDataCallback, base::Unretained(this),
- parallel_operation_index, entry, next_offset + expected_read_size,
- data_len, expected_read_size);
- int new_result = entry->ReadData(
- 1, next_offset, read_buffers_[parallel_operation_index].get(), kChunkSize,
- callback);
- if (new_result != net::ERR_IO_PENDING)
- callback.Run(new_result);
- }
- bool ReadHandler::CheckForErrorAndCancel(int result) {
- DCHECK_NE(net::ERR_IO_PENDING, result);
- if (result != net::OK && !(result > 0))
- pending_result_ = result;
- if (pending_result_ != net::OK) {
- --pending_operations_count_;
- if (pending_operations_count_ == 0)
- std::move(final_callback_).Run(pending_result_);
- return true;
- }
- return false;
- }
- bool DiskCachePerfTest::TimeWrites(const std::string& story) {
- for (size_t i = 0; i < kNumEntries; i++) {
- TestEntry entry;
- entry.key = GenerateKey(true);
- entry.data_len = base::RandInt(0, kBodySize);
- entries_.push_back(entry);
- }
- net::TestCompletionCallback cb;
- auto reporter = SetUpDiskCacheReporter(story);
- base::ElapsedTimer write_timer;
- WriteHandler write_handler(this, cache_.get(), cb.callback());
- write_handler.Run();
- auto result = cb.WaitForResult();
- reporter.AddResult(kMetricCacheEntriesWriteTimeMs,
- write_timer.Elapsed().InMillisecondsF());
- return result == net::OK;
- }
- bool DiskCachePerfTest::TimeReads(WhatToRead what_to_read,
- const std::string& metric,
- const std::string& story) {
- auto reporter = SetUpDiskCacheReporter(story);
- base::ElapsedTimer timer;
- net::TestCompletionCallback cb;
- ReadHandler read_handler(this, what_to_read, cache_.get(), cb.callback());
- read_handler.Run();
- auto result = cb.WaitForResult();
- reporter.AddResult(metric, timer.Elapsed().InMillisecondsF());
- return result == net::OK;
- }
- TEST_F(DiskCachePerfTest, BlockfileHashes) {
- auto reporter = SetUpDiskCacheReporter("baseline_story");
- base::ElapsedTimer timer;
- for (int i = 0; i < 300000; i++) {
- std::string key = GenerateKey(true);
- // TODO(dcheng): It's unclear if this is sufficient to keep a sufficiently
- // smart optimizer from simply discarding the function call if it realizes
- // there are no side effects.
- base::PersistentHash(key);
- }
- reporter.AddResult(kMetricCacheKeysHashTimeMs,
- timer.Elapsed().InMillisecondsF());
- }
- void DiskCachePerfTest::ResetAndEvictSystemDiskCache() {
- base::RunLoop().RunUntilIdle();
- cache_.reset();
- // Flush all files in the cache out of system memory.
- const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*");
- base::FileEnumerator enumerator(cache_path_, true /* recursive */,
- base::FileEnumerator::FILES, file_pattern);
- for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
- file_path = enumerator.Next()) {
- ASSERT_TRUE(base::EvictFileFromSystemCache(file_path));
- }
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
- // And, cache directories, on platforms where the eviction utility supports
- // this (currently Linux and Android only).
- if (simple_cache_mode_) {
- ASSERT_TRUE(
- base::EvictFileFromSystemCache(cache_path_.AppendASCII("index-dir")));
- }
- ASSERT_TRUE(base::EvictFileFromSystemCache(cache_path_));
- #endif
- DisableFirstCleanup();
- InitCache();
- }
- void DiskCachePerfTest::CacheBackendPerformance(const std::string& story) {
- base::test::ScopedRunLoopTimeout default_timeout(
- FROM_HERE, TestTimeouts::action_max_timeout());
- LOG(ERROR) << "Using cache at:" << cache_path_.MaybeAsASCII();
- SetMaxSize(500 * 1024 * 1024);
- InitCache();
- EXPECT_TRUE(TimeWrites(story));
- disk_cache::FlushCacheThreadForTesting();
- base::RunLoop().RunUntilIdle();
- ResetAndEvictSystemDiskCache();
- EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_ONLY,
- kMetricCacheHeadersReadTimeColdMs, story));
- EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_ONLY,
- kMetricCacheHeadersReadTimeWarmMs, story));
- disk_cache::FlushCacheThreadForTesting();
- base::RunLoop().RunUntilIdle();
- ResetAndEvictSystemDiskCache();
- EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_AND_BODY,
- kMetricCacheEntriesReadTimeColdMs, story));
- EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_AND_BODY,
- kMetricCacheEntriesReadTimeWarmMs, story));
- disk_cache::FlushCacheThreadForTesting();
- base::RunLoop().RunUntilIdle();
- }
- #if BUILDFLAG(IS_FUCHSIA)
- // TODO(crbug.com/851083): Fix this test on Fuchsia and re-enable.
- #define MAYBE_CacheBackendPerformance DISABLED_CacheBackendPerformance
- #else
- #define MAYBE_CacheBackendPerformance CacheBackendPerformance
- #endif
- TEST_F(DiskCachePerfTest, MAYBE_CacheBackendPerformance) {
- CacheBackendPerformance("blockfile_cache");
- }
- #if BUILDFLAG(IS_FUCHSIA)
- // TODO(crbug.com/851083): Fix this test on Fuchsia and re-enable.
- #define MAYBE_SimpleCacheBackendPerformance \
- DISABLED_SimpleCacheBackendPerformance
- #else
- #define MAYBE_SimpleCacheBackendPerformance SimpleCacheBackendPerformance
- #endif
- TEST_F(DiskCachePerfTest, MAYBE_SimpleCacheBackendPerformance) {
- SetSimpleCacheMode();
- CacheBackendPerformance("simple_cache");
- }
- // Creating and deleting "entries" on a block-file is something quite frequent
- // (after all, almost everything is stored on block files). The operation is
- // almost free when the file is empty, but can be expensive if the file gets
- // fragmented, or if we have multiple files. This test measures that scenario,
- // by using multiple, highly fragmented files.
- TEST_F(DiskCachePerfTest, BlockFilesPerformance) {
- ASSERT_TRUE(CleanupCacheDir());
- disk_cache::BlockFiles files(cache_path_);
- ASSERT_TRUE(files.Init(true));
- const int kNumBlocks = 60000;
- disk_cache::Addr address[kNumBlocks];
- auto reporter = SetUpDiskCacheReporter("blockfile_cache");
- base::ElapsedTimer sequential_timer;
- // Fill up the 32-byte block file (use three files).
- for (auto& addr : address) {
- int block_size = base::RandInt(1, 4);
- EXPECT_TRUE(files.CreateBlock(disk_cache::RANKINGS, block_size, &addr));
- }
- reporter.AddResult(kMetricFillBlocksTimeMs,
- sequential_timer.Elapsed().InMillisecondsF());
- base::ElapsedTimer random_timer;
- for (int i = 0; i < 200000; i++) {
- int block_size = base::RandInt(1, 4);
- int entry = base::RandInt(0, kNumBlocks - 1);
- files.DeleteBlock(address[entry], false);
- EXPECT_TRUE(
- files.CreateBlock(disk_cache::RANKINGS, block_size, &address[entry]));
- }
- reporter.AddResult(kMetricCreateDeleteBlocksTimeMs,
- random_timer.Elapsed().InMillisecondsF());
- base::RunLoop().RunUntilIdle();
- }
- void VerifyRvAndCallClosure(base::RepeatingClosure* c, int expect_rv, int rv) {
- EXPECT_EQ(expect_rv, rv);
- c->Run();
- }
- TEST_F(DiskCachePerfTest, SimpleCacheInitialReadPortion) {
- // A benchmark that aims to measure how much time we take in I/O thread
- // for initial bookkeeping before returning to the caller, and how much
- // after (batched up some). The later portion includes some event loop
- // overhead.
- const int kBatchSize = 100;
- SetSimpleCacheMode();
- InitCache();
- // Write out the entries, and keep their objects around.
- scoped_refptr<net::IOBuffer> buffer1 =
- base::MakeRefCounted<net::IOBuffer>(kHeadersSize);
- scoped_refptr<net::IOBuffer> buffer2 =
- base::MakeRefCounted<net::IOBuffer>(kBodySize);
- CacheTestFillBuffer(buffer1->data(), kHeadersSize, false);
- CacheTestFillBuffer(buffer2->data(), kBodySize, false);
- disk_cache::Entry* cache_entry[kBatchSize];
- for (int i = 0; i < kBatchSize; ++i) {
- TestEntryResultCompletionCallback cb_create;
- disk_cache::EntryResult result = cb_create.GetResult(cache_->CreateEntry(
- base::NumberToString(i), net::HIGHEST, cb_create.callback()));
- ASSERT_EQ(net::OK, result.net_error());
- cache_entry[i] = result.ReleaseEntry();
- net::TestCompletionCallback cb;
- int rv = cache_entry[i]->WriteData(0, 0, buffer1.get(), kHeadersSize,
- cb.callback(), false);
- ASSERT_EQ(kHeadersSize, cb.GetResult(rv));
- rv = cache_entry[i]->WriteData(1, 0, buffer2.get(), kBodySize,
- cb.callback(), false);
- ASSERT_EQ(kBodySize, cb.GetResult(rv));
- }
- // Now repeatedly read these, batching up the waiting to try to
- // account for the two portions separately. Note that we need separate entries
- // since we are trying to keep interesting work from being on the delayed-done
- // portion.
- const int kIterations = 50000;
- double elapsed_early = 0.0;
- double elapsed_late = 0.0;
- for (int i = 0; i < kIterations; ++i) {
- base::RunLoop event_loop;
- base::RepeatingClosure barrier =
- base::BarrierClosure(kBatchSize, event_loop.QuitWhenIdleClosure());
- net::CompletionRepeatingCallback cb_batch(base::BindRepeating(
- VerifyRvAndCallClosure, base::Unretained(&barrier), kHeadersSize));
- base::ElapsedTimer timer_early;
- for (auto* entry : cache_entry) {
- int rv = entry->ReadData(0, 0, buffer1.get(), kHeadersSize, cb_batch);
- if (rv != net::ERR_IO_PENDING) {
- barrier.Run();
- ASSERT_EQ(kHeadersSize, rv);
- }
- }
- elapsed_early += timer_early.Elapsed().InMillisecondsF();
- base::ElapsedTimer timer_late;
- event_loop.Run();
- elapsed_late += timer_late.Elapsed().InMillisecondsF();
- }
- // Cleanup
- for (auto* entry : cache_entry)
- entry->Close();
- disk_cache::FlushCacheThreadForTesting();
- base::RunLoop().RunUntilIdle();
- auto reporter = SetUpDiskCacheReporter("early_portion");
- reporter.AddResult(kMetricSimpleCacheInitTotalTimeMs, elapsed_early);
- reporter.AddResult(kMetricSimpleCacheInitPerEntryTimeUs,
- 1000 * (elapsed_early / (kIterations * kBatchSize)));
- reporter = SetUpDiskCacheReporter("event_loop_portion");
- reporter.AddResult(kMetricSimpleCacheInitTotalTimeMs, elapsed_late);
- reporter.AddResult(kMetricSimpleCacheInitPerEntryTimeUs,
- 1000 * (elapsed_late / (kIterations * kBatchSize)));
- }
- #if BUILDFLAG(IS_FUCHSIA)
- // TODO(crbug.com/1318120): Fix this test on Fuchsia and re-enable.
- #define MAYBE_EvictionPerformance DISABLED_EvictionPerformance
- #else
- #define MAYBE_EvictionPerformance EvictionPerformance
- #endif
- // Measures how quickly SimpleIndex can compute which entries to evict.
- TEST(SimpleIndexPerfTest, MAYBE_EvictionPerformance) {
- const int kEntries = 10000;
- class NoOpDelegate : public disk_cache::SimpleIndexDelegate {
- void DoomEntries(std::vector<uint64_t>* entry_hashes,
- net::CompletionOnceCallback callback) override {}
- };
- NoOpDelegate delegate;
- base::Time start(base::Time::Now());
- double evict_elapsed_ms = 0;
- int iterations = 0;
- while (iterations < 61000) {
- ++iterations;
- disk_cache::SimpleIndex index(/* io_thread = */ nullptr,
- /* cleanup_tracker = */ nullptr, &delegate,
- net::DISK_CACHE,
- /* simple_index_file = */ nullptr);
- // Make sure large enough to not evict on insertion.
- index.SetMaxSize(kEntries * 2);
- for (int i = 0; i < kEntries; ++i) {
- index.InsertEntryForTesting(
- i, disk_cache::EntryMetadata(start + base::Seconds(i), 1u));
- }
- // Trigger an eviction.
- base::ElapsedTimer timer;
- index.SetMaxSize(kEntries);
- index.UpdateEntrySize(0, 1u);
- evict_elapsed_ms += timer.Elapsed().InMillisecondsF();
- }
- auto reporter = SetUpSimpleIndexReporter("baseline_story");
- reporter.AddResult(kMetricAverageEvictionTimeMs,
- evict_elapsed_ms / iterations);
- }
- } // namespace
|