Convert BlockCache from LFU to LRU

In practice there were usually <10 calls to Get per call to Age,
resulting in everything but the most recently used block having an
access count of 0. This resulted in it having essentially random
eviction, which worked decently due to the size of the cache, but with a
significant speed overhead for the LFU tracking.

Originally committed to SVN as r6440.
This commit is contained in:
Thomas Goyne 2012-02-02 22:58:06 +00:00
parent 7ca0ad3233
commit fc932dddc7

View file

@ -103,8 +103,8 @@ class DataBlockCache {
/// DOCME /// DOCME
struct MacroBlock { struct MacroBlock {
/// How many times data in the macroblock has been accessed /// How long has it been since this macroblock was accessed?
int access_count; int age;
/// The blocks contained in the macroblock /// The blocks contained in the macroblock
BlockArray blocks; BlockArray blocks;
}; };
@ -124,15 +124,13 @@ class DataBlockCache {
/// Factory object for blocks /// Factory object for blocks
BlockFactoryT factory; BlockFactoryT factory;
/// Used in sorting the macroblocks by accesas count for aging /// Used in sorting the macroblocks by age
static bool comp_access_count(const MacroBlock *lft, const MacroBlock *rgt) { return lft->access_count > rgt->access_count; } static bool comp_age(const MacroBlock *lft, const MacroBlock *rgt) { return lft->age < rgt->age; }
/// @brief Dispose of all blocks in a macroblock and mark it empty /// @brief Dispose of all blocks in a macroblock and mark it empty
/// @param mb_index Index of macroblock to clear /// @param mb_index Index of macroblock to clear
void KillMacroBlock(MacroBlock &mb) void KillMacroBlock(MacroBlock &mb)
{ {
mb.access_count = 0;
for (size_t bi = 0; bi < mb.blocks.size(); ++bi) for (size_t bi = 0; bi < mb.blocks.size(); ++bi)
{ {
BlockT *b = mb.blocks[bi]; BlockT *b = mb.blocks[bi];
@ -208,31 +206,26 @@ public:
// Get a list of macro blocks sorted by access count // Get a list of macro blocks sorted by access count
std::vector<MacroBlock*> access_data; std::vector<MacroBlock*> access_data;
access_data.resize(data.size()); access_data.reserve(data.size());
size_t access_data_count = 0;
// For whatever reason, G++ pukes if I try using iterators here... // For whatever reason, G++ pukes if I try using iterators here...
for (size_t mbi = 0; mbi != data.size(); ++mbi) for (size_t mbi = 0; mbi != data.size(); ++mbi)
{ {
if (data[mbi].blocks.size()) if (data[mbi].blocks.size())
access_data[access_data_count++] = &data[mbi]; access_data.push_back(&data[mbi]);
} }
sort(access_data.begin(), access_data.begin() + access_data_count, comp_access_count); sort(access_data.begin(), access_data.end(), comp_age);
// Sum up data size until we hit the max // Sum up data size until we hit the max
size_t cur_size = 0; size_t cur_size = 0;
size_t block_size = factory.GetBlockSize(); size_t block_size = factory.GetBlockSize();
size_t mbi = 0; size_t mbi = 0;
for (; mbi < access_data_count && cur_size < max_size; ++mbi) for (; mbi < access_data.size() && cur_size < max_size; ++mbi)
{ {
BlockArray &ba = access_data[mbi]->blocks; BlockArray &ba = access_data[mbi]->blocks;
cur_size += (ba.size() - std::count(ba.begin(), ba.end(), (BlockT*)0)) * block_size; cur_size += (ba.size() - std::count(ba.begin(), ba.end(), (BlockT*)0)) * block_size;
// Cut access count in half for live blocks, so parts that don't get accessed
// a lot will eventually be killed off.
access_data[mbi]->access_count /= 2;
} }
// Hit max, clear all remaining blocks // Hit max, clear all remaining blocks
for (++mbi; mbi < access_data_count; ++mbi) for (++mbi; mbi < access_data.size(); ++mbi)
{ {
KillMacroBlock(*access_data[mbi]); KillMacroBlock(*access_data[mbi]);
} }
@ -250,8 +243,14 @@ public:
size_t mbi = i >> MacroblockExponent; size_t mbi = i >> MacroblockExponent;
assert(mbi < data.size()); assert(mbi < data.size());
// Age all of the other macroblocks
for (size_t idx = 0; idx < data.size(); ++idx)
{
data[idx].age += 1;
}
MacroBlock &mb = data[mbi]; MacroBlock &mb = data[mbi];
mb.access_count += 1; mb.age = 0;
if (mb.blocks.size() == 0) if (mb.blocks.size() == 0)
{ {