diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 22:42:52 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 22:42:52 +0000 |
commit | 586acc5fe142f498261f52c66862fa417c3d52d2 (patch) | |
tree | c98b3417a883f2477029c8cd5888f4078681e24e /net/disk_cache/stats.cc | |
parent | a814a8d55429605fe6d7045045cd25b6bf624580 (diff) | |
download | chromium_src-586acc5fe142f498261f52c66862fa417c3d52d2.zip chromium_src-586acc5fe142f498261f52c66862fa417c3d52d2.tar.gz chromium_src-586acc5fe142f498261f52c66862fa417c3d52d2.tar.bz2 |
Add net to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache/stats.cc')
-rw-r--r-- | net/disk_cache/stats.cc | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/net/disk_cache/stats.cc b/net/disk_cache/stats.cc new file mode 100644 index 0000000..5a5df7c --- /dev/null +++ b/net/disk_cache/stats.cc @@ -0,0 +1,258 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "net/disk_cache/stats.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "net/disk_cache/backend_impl.h" + +namespace { + +const int32 kDiskSignature = 0xF01427E0; + +struct OnDiskStats { + int32 signature; + int size; + int data_sizes[disk_cache::Stats::kDataSizesLength]; + int64 counters[disk_cache::Stats::MAX_COUNTER]; +}; + +// Returns the "floor" (as opposed to "ceiling") of log base 2 of number. +int LogBase2(int32 number) { + unsigned int value = static_cast<unsigned int>(number); + const unsigned int mask[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; + const unsigned int s[] = {1, 2, 4, 8, 16}; + + unsigned int result = 0; + for (int i = 4; i >= 0; i--) { + if (value & mask[i]) { + value >>= s[i]; + result |= s[i]; + } + } + return static_cast<int>(result); +} + +static const char* kCounterNames[] = { + "Open miss", + "Open hit", + "Create miss", + "Create hit", + "Create error", + "Trim entry", + "Doom entry", + "Doom cache", + "Invalid entry", + "Open entries", + "Max entries", + "Timer", + "Read data", + "Write data", + "Open rankings", + "Get rankings", + "Fatal error", +}; +COMPILE_ASSERT(arraysize(kCounterNames) == disk_cache::Stats::MAX_COUNTER, + update_the_names); + +} // namespace + +namespace disk_cache { + +bool LoadStats(BackendImpl* backend, Addr address, OnDiskStats* stats) { + MappedFile* file = backend->File(address); + if (!file) + return false; + + size_t offset = address.start_block() * address.BlockSize() + + kBlockHeaderSize; + if (!file->Read(stats, sizeof(*stats), offset)) + return false; + + if (stats->signature != kDiskSignature) + return false; + + // We don't want to discard the whole cache everytime we have one extra + // counter; just reset them to zero. + if (stats->size != sizeof(*stats)) + memset(stats, 0, sizeof(*stats)); + + return true; +} + +bool StoreStats(BackendImpl* backend, Addr address, OnDiskStats* stats) { + MappedFile* file = backend->File(address); + if (!file) + return false; + + size_t offset = address.start_block() * address.BlockSize() + + kBlockHeaderSize; + return file->Write(stats, sizeof(*stats), offset); +} + +bool CreateStats(BackendImpl* backend, Addr* address, OnDiskStats* stats) { + if (!backend->CreateBlock(BLOCK_256, 2, address)) + return false; + + // If we have more than 512 bytes of counters, change kDiskSignature so we + // don't overwrite something else (LoadStats must fail). + COMPILE_ASSERT(sizeof(*stats) <= 256 * 2, use_more_blocks); + memset(stats, 0, sizeof(*stats)); + stats->signature = kDiskSignature; + stats->size = sizeof(*stats); + + return StoreStats(backend, *address, stats); +} + +bool Stats::Init(BackendImpl* backend, uint32* storage_addr) { + backend_ = backend; + + OnDiskStats stats; + Addr address(*storage_addr); + if (address.is_initialized()) { + if (!LoadStats(backend, address, &stats)) + return false; + } else { + if (!CreateStats(backend, &address, &stats)) + return false; + *storage_addr = address.value(); + } + + storage_addr_ = address.value(); + + memcpy(data_sizes_, stats.data_sizes, sizeof(data_sizes_)); + memcpy(counters_, stats.counters, sizeof(counters_)); + + return true; +} + +Stats::~Stats() { + if (!backend_) + return; + + OnDiskStats stats; + stats.signature = kDiskSignature; + stats.size = sizeof(stats); + memcpy(stats.data_sizes, data_sizes_, sizeof(data_sizes_)); + memcpy(stats.counters, counters_, sizeof(counters_)); + + Addr address(storage_addr_); + StoreStats(backend_, address, &stats); +} + +// The array will be filled this way: +// index size +// 0 [0, 1024) +// 1 [1024, 2048) +// 2 [2048, 4096) +// 3 [4K, 6K) +// ... +// 10 [18K, 20K) +// 11 [20K, 24K) +// 12 [24k, 28K) +// ... +// 15 [36k, 40K) +// 16 [40k, 64K) +// 17 [64K, 128K) +// 18 [128K, 256K) +// ... +// 23 [4M, 8M) +// 24 [8M, 16M) +// 25 [16M, 32M) +// 26 [32M, 64M) +// 27 [64M, ...) +int Stats::GetStatsBucket(int32 size) { + if (size < 1024) + return 0; + + // 10 slots more, until 20K. + if (size < 20 * 1024) + return size / 2048 + 1; + + // 5 slots more, from 20K to 40K. + if (size < 40 * 1024) + return (size - 20 * 1024) / 4096 + 11; + + // From this point on, use a logarithmic scale. + int result = LogBase2(size) + 1; + + COMPILE_ASSERT(kDataSizesLength > 16, update_the_scale); + if (result >= kDataSizesLength) + result = kDataSizesLength - 1; + + return result; +} + +void Stats::ModifyStorageStats(int32 old_size, int32 new_size) { + // We keep a counter of the data block size on an array where each entry is + // the adjusted log base 2 of the size. The first entry counts blocks of 256 + // bytes, the second blocks up to 512 bytes, etc. With 20 entries, the last + // one stores entries of more than 64 MB + int new_index = GetStatsBucket(new_size); + int old_index = GetStatsBucket(old_size); + + if (new_size) + data_sizes_[new_index]++; + + if (old_size) + data_sizes_[old_index]--; +} + +void Stats::OnEvent(Counters an_event) { + DCHECK(an_event > MIN_COUNTER || an_event < MAX_COUNTER); + counters_[an_event]++; +} + +void Stats::SetCounter(Counters counter, int64 value) { + DCHECK(counter > MIN_COUNTER || counter < MAX_COUNTER); + counters_[counter] = value; +} + +int64 Stats::GetCounter(Counters counter) const { + DCHECK(counter > MIN_COUNTER || counter < MAX_COUNTER); + return counters_[counter]; +} + +void Stats::GetItems(StatsItems* items) { + std::pair<std::string, std::string> item; + for (int i = 0; i < kDataSizesLength; i++) { + item.first = StringPrintf("Size%02d", i); + item.second = StringPrintf("0x%08x", data_sizes_[i]); + items->push_back(item); + } + + for (int i = MIN_COUNTER + 1; i < MAX_COUNTER; i++) { + item.first = kCounterNames[i]; + item.second = StringPrintf("0x%I64x", counters_[i]); + items->push_back(item); + } +} + +} // namespace disk_cache |