Skip to content

Commit

Permalink
Merge pull request #16 from chenhao-ye/reuse-distance
Browse files Browse the repository at this point in the history
Use Reuse Distance Histogram for Cache Stat
  • Loading branch information
chenhao-ye authored Oct 25, 2024
2 parents 45a8d4b + 50edfb2 commit ef2a538
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 27 deletions.
65 changes: 42 additions & 23 deletions include/gcache/ghost_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,17 @@ class GhostCache {
std::vector<Node_t*> boundaries;
std::vector<CacheStat> caches_stat;

// the reused distances are formatted as a histogram
std::vector<uint32_t> reuse_distances; // converted to caches_stat lazily
uint32_t reuse_count; // count all access to reuse_distances

Handle_t access_impl(uint32_t block_id, uint32_t hash, AccessMode mode);

template <uint32_t S, typename H>
friend class SampledGhostKvCache;

void build_caches_stat();

public:
GhostCache(uint32_t tick, uint32_t min_size, uint32_t max_size)
: tick(tick),
Expand All @@ -67,7 +73,9 @@ class GhostCache {
num_ticks((max_size - min_size) / tick + 1),
cache(),
boundaries(num_ticks - 1, nullptr),
caches_stat(num_ticks) {
caches_stat(num_ticks),
reuse_distances(num_ticks, 0),
reuse_count(0) {
assert(tick > 0);
assert(min_size > 1); // otherwise the first boundary will be LRU evicted
assert(min_size + (num_ticks - 1) * tick == max_size);
Expand All @@ -83,23 +91,27 @@ class GhostCache {
[[nodiscard]] uint32_t get_min_size() const { return min_size; }
[[nodiscard]] uint32_t get_max_size() const { return max_size; }

[[nodiscard]] const CacheStat& get_stat(uint32_t cache_size) const {
[[nodiscard]] const CacheStat& get_stat(uint32_t cache_size) {
assert(cache_size >= min_size);
assert(cache_size <= max_size);
assert((cache_size - min_size) % tick == 0);
uint32_t size_idx = (cache_size - min_size) / tick;
assert(size_idx < num_ticks);
return caches_stat[size_idx];
const CacheStat& stat = caches_stat[size_idx];
if (stat.hit_cnt + stat.miss_cnt != reuse_count) build_caches_stat();
assert(stat.hit_cnt + stat.miss_cnt == reuse_count);
return stat;
}
[[nodiscard]] double get_hit_rate(uint32_t cache_size) const {
[[nodiscard]] double get_hit_rate(uint32_t cache_size) {
return get_stat(cache_size).get_hit_rate();
}
[[nodiscard]] double get_miss_rate(uint32_t cache_size) const {
[[nodiscard]] double get_miss_rate(uint32_t cache_size) {
return get_stat(cache_size).get_miss_rate();
}

void reset_stat() {
for (auto& s : caches_stat) s.reset();
reuse_count = 0;
for (size_t i = 0; i < reuse_distances.size(); ++i) reuse_distances[i] = 0;
}

// For each item in the LRU list, call fn in LRU order
Expand Down Expand Up @@ -147,8 +159,8 @@ class GhostCache {
}

public:
std::ostream& print(std::ostream& os, int indent = 0) const;
friend std::ostream& operator<<(std::ostream& os, const GhostCache& c) {
std::ostream& print(std::ostream& os, int indent = 0);
friend std::ostream& operator<<(std::ostream& os, GhostCache& c) {
return c.print(os);
}
};
Expand Down Expand Up @@ -186,22 +198,21 @@ class SampledGhostCache : public GhostCache<Hash, Meta> {
return this->max_size << SampleShift;
}

[[nodiscard]] const CacheStat& get_stat(uint32_t cache_size) const {
[[nodiscard]] const CacheStat& get_stat(uint32_t cache_size) {
return get_stat_shifted(cache_size >> SampleShift);
}
[[nodiscard]] double get_hit_rate(uint32_t cache_size) const {
[[nodiscard]] double get_hit_rate(uint32_t cache_size) {
return this->get_stat(cache_size).get_hit_rate();
}
[[nodiscard]] double get_miss_rate(uint32_t cache_size) const {
[[nodiscard]] double get_miss_rate(uint32_t cache_size) {
return this->get_stat(cache_size).get_miss_rate();
}

protected:
template <uint32_t S, typename H>
friend class SampledGhostKvCache;

[[nodiscard]] const CacheStat& get_stat_shifted(
uint32_t cache_size_shifted) const {
[[nodiscard]] const CacheStat& get_stat_shifted(uint32_t cache_size_shifted) {
return GhostCache<Hash, Meta>::get_stat(cache_size_shifted);
}
};
Expand Down Expand Up @@ -270,29 +281,37 @@ GhostCache<Hash, Meta>::access_impl(uint32_t block_id, uint32_t hash,

switch (mode) {
case AccessMode::DEFAULT:
if (s) {
for (uint32_t i = 0; i < size_idx; ++i) caches_stat[i].add_miss();
for (uint32_t i = size_idx; i < num_ticks; ++i)
caches_stat[i].add_hit();
} else {
for (uint32_t i = 0; i < num_ticks; ++i) caches_stat[i].add_miss();
}
// if no successor,it must be a miss for all cache sizes
if (s) ++reuse_distances[size_idx];
++reuse_count;
break;
case AccessMode::AS_MISS:
for (uint32_t i = 0; i < num_ticks; ++i) caches_stat[i].add_miss();
++reuse_count;
break;
case AccessMode::AS_HIT:
for (uint32_t i = 0; i < num_ticks; ++i) caches_stat[i].add_hit();
++reuse_distances[0];
++reuse_count;
break;
case AccessMode::NOOP:
break;
}
return h;
}

template <typename Hash, typename Meta>
inline void GhostCache<Hash, Meta>::build_caches_stat() {
uint32_t accum_hit_cnt = 0;
for (size_t idx = 0; idx < caches_stat.size(); ++idx) {
accum_hit_cnt += reuse_distances[idx];
caches_stat[idx].hit_cnt = accum_hit_cnt;
caches_stat[idx].miss_cnt = reuse_count - accum_hit_cnt;
}
}

template <typename Hash, typename Meta>
inline std::ostream& GhostCache<Hash, Meta>::print(std::ostream& os,
int indent) const {
int indent) {
build_caches_stat();
os << "GhostCache (tick=" << tick << ", min=" << min_size
<< ", max=" << max_size << ", num_ticks=" << num_ticks
<< ", size=" << cache.size() << ") {\n";
Expand Down
8 changes: 4 additions & 4 deletions include/gcache/ghost_kv_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ class SampledGhostKvCache {
[[nodiscard]] uint32_t get_max_count() const {
return ghost_cache.get_max_size();
}
[[nodiscard]] double get_hit_rate(uint32_t count) const {
[[nodiscard]] double get_hit_rate(uint32_t count) {
return ghost_cache.get_hit_rate(count);
}
[[nodiscard]] double get_miss_rate(uint32_t count) const {
[[nodiscard]] double get_miss_rate(uint32_t count) {
return ghost_cache.get_miss_rate(count);
}
[[nodiscard]] const CacheStat& get_stat(uint32_t count) const {
[[nodiscard]] const CacheStat& get_stat(uint32_t count) {
return ghost_cache.get_stat(count);
}

Expand Down Expand Up @@ -90,7 +90,7 @@ class SampledGhostKvCache {

[[nodiscard]] const std::vector<std::tuple<
/*count*/ uint32_t, /*size*/ uint32_t, /*miss_rate*/ CacheStat>>
get_cache_stat_curve() const {
get_cache_stat_curve() {
std::vector<std::tuple<uint32_t, uint32_t, CacheStat>> curve;
uint32_t curr_count = 0;
uint32_t curr_size = 0;
Expand Down

0 comments on commit ef2a538

Please sign in to comment.