From 4b1f333b83d98fad7d555c56974df8f4443f0ced Mon Sep 17 00:00:00 2001 From: Chenhao Ye Date: Fri, 1 Dec 2023 17:10:19 -0700 Subject: [PATCH 1/2] add access mode support --- include/gcache/ghost_cache.h | 43 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/include/gcache/ghost_cache.h b/include/gcache/ghost_cache.h index 56ed744..78124d5 100644 --- a/include/gcache/ghost_cache.h +++ b/include/gcache/ghost_cache.h @@ -77,7 +77,14 @@ class GhostCache { std::vector size_boundaries; std::vector caches_stat; - void access_impl(uint32_t block_id, uint32_t hash); + // AccessMode controls the behavior to update cache stat + enum AccessMode : uint8_t { + DEFAULT, // update normally + AS_MISS, // consider it as a miss for all cache sizes + AS_HIT, // consider it as a hit for all cache sizes + NOOP, // do not update + }; + void access_impl(uint32_t block_id, uint32_t hash, AccessMode mode); public: GhostCache(uint32_t tick, uint32_t min_size, uint32_t max_size) @@ -94,7 +101,9 @@ class GhostCache { assert(min_size + (num_ticks - 1) * tick == max_size); cache.init(max_size); } - void access(uint32_t block_id) { access_impl(block_id, ghash{}(block_id)); } + void access(uint32_t block_id, AccessMode mode = AccessMode::DEFAULT) { + access_impl(block_id, ghash{}(block_id), mode); + } [[nodiscard]] uint32_t get_tick() const { return tick; } [[nodiscard]] uint32_t get_min_size() const { return min_size; } @@ -141,9 +150,9 @@ class SampledGhostCache : public GhostCache { } // Only update ghost cache if the first few bits of hash is all zero - void access(uint32_t block_id) { + void access(uint32_t block_id, AccessMode mode = AccessMode::DEFAULT) { uint32_t hash = ghash{}(block_id); - if ((hash >> (32 - SampleShift)) == 0) access_impl(block_id, hash); + if ((hash >> (32 - SampleShift)) == 0) access_impl(block_id, hash, mode); } uint32_t get_tick() const { return tick << SampleShift; } @@ -168,7 +177,8 @@ class SampledGhostCache : public GhostCache { /** * When using ghost cache, we assume in_use list is always empty. */ -inline void GhostCache::access_impl(uint32_t block_id, uint32_t hash) { +inline void GhostCache::access_impl(uint32_t block_id, uint32_t hash, + AccessMode mode) { uint32_t size_idx; Handle_t s; // successor Handle_t h = cache.refresh(block_id, hash, s); @@ -210,11 +220,24 @@ inline void GhostCache::access_impl(uint32_t block_id, uint32_t hash) { b->value++; b = b->next; } - 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(); + 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(); + } + break; + case AccessMode::AS_MISS: + for (uint32_t i = 0; i < num_ticks; ++i) caches_stat[i].add_miss(); + break; + case AccessMode::AS_HIT: + for (uint32_t i = 0; i < num_ticks; ++i) caches_stat[i].add_hit(); + break; + case AccessMode::NOOP: + break; } *h = 0; From 9a03ecea23bdfb4c34c7b8ff14cf773a18314f16 Mon Sep 17 00:00:00 2001 From: Chenhao Ye Date: Fri, 1 Dec 2023 18:25:50 -0600 Subject: [PATCH 2/2] update ghost test --- include/gcache/ghost_cache.h | 15 +++++++------ tests/test_ghost.cpp | 42 +++++++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/include/gcache/ghost_cache.h b/include/gcache/ghost_cache.h index 78124d5..b7eb435 100644 --- a/include/gcache/ghost_cache.h +++ b/include/gcache/ghost_cache.h @@ -15,6 +15,14 @@ namespace gcache { +// AccessMode controls the behavior to update cache stat +enum AccessMode : uint8_t { + DEFAULT, // update normally + AS_MISS, // consider it as a miss for all cache sizes + AS_HIT, // consider it as a hit for all cache sizes + NOOP, // do not update +}; + struct CacheStat { uint64_t hit_cnt; uint64_t miss_cnt; @@ -77,13 +85,6 @@ class GhostCache { std::vector size_boundaries; std::vector caches_stat; - // AccessMode controls the behavior to update cache stat - enum AccessMode : uint8_t { - DEFAULT, // update normally - AS_MISS, // consider it as a miss for all cache sizes - AS_HIT, // consider it as a hit for all cache sizes - NOOP, // do not update - }; void access_impl(uint32_t block_id, uint32_t hash, AccessMode mode); public: diff --git a/tests/test_ghost.cpp b/tests/test_ghost.cpp index 62da74e..0fc9c7f 100644 --- a/tests/test_ghost.cpp +++ b/tests/test_ghost.cpp @@ -24,21 +24,38 @@ void test1() { ghost_cache.access(1); ghost_cache.access(2); ghost_cache.access(3); - std::cout - << "Expect: Boundaries: [1, 0, (null), (null)]; Stat: [0/4, 0/4, 0/4]\n"; + std::cout << "Expect: Boundaries: [1, 0, (null), (null)]; " + "Stat: [0/4, 0/4, 0/4, 0/4]\n"; std::cout << ghost_cache; ghost_cache.access(4); ghost_cache.access(5); - std::cout << "Expect: Boundaries: [3, 2, 1, 0]; Stat: [0/6, 0/6, 0/6]\n"; + std::cout << "Expect: Boundaries: [3, 2, 1, 0]; Stat: [0/6, 0/6, 0/6, 0/6]\n"; std::cout << ghost_cache; ghost_cache.access(2); - std::cout << "Expect: Boundaries: [4, 3, 1, 0]; Stat: [0/7, 1/7, 1/7]\n"; + std::cout << "Expect: Boundaries: [4, 3, 1, 0]; Stat: [0/7, 1/7, 1/7, 1/7]\n"; std::cout << ghost_cache; ghost_cache.access(4); - std::cout << "Expect: Boundaries: [5, 3, 1, 0]; Stat: [1/8, 2/8, 2/8]\n"; + std::cout << "Expect: Boundaries: [5, 3, 1, 0]; Stat: [1/8, 2/8, 2/8, 2/8]\n"; + std::cout << ghost_cache; + std::cout << std::flush; + + ghost_cache.access(2, AccessMode::AS_MISS); + std::cout << "Expect: Boundaries: [5, 3, 1, 0]; Stat: [1/9, 2/9, 2/9, 2/9]\n"; + std::cout << ghost_cache; + std::cout << std::flush; + + ghost_cache.access(0, AccessMode::AS_HIT); + std::cout + << "Expect: Boundaries: [4, 5, 3, 1]; Stat: [2/10, 3/10, 3/10, 3/10]\n"; + std::cout << ghost_cache; + std::cout << std::flush; + + ghost_cache.access(7, AccessMode::NOOP); + std::cout + << "Expect: Boundaries: [2, 4, 5, 3]; Stat: [2/10, 3/10, 3/10, 3/10]\n"; std::cout << ghost_cache; std::cout << std::flush; } @@ -72,6 +89,21 @@ void test2() { std::cout << "Expect: Boundaries: [1, 6, 3]; Stat: [0/10, 0/10, 1/10]\n"; std::cout << ghost_cache; std::cout << std::flush; + + ghost_cache.access(8, AccessMode::NOOP); + std::cout << "Expect: Boundaries: [4, 7, 5]; Stat: [0/10, 0/10, 1/10]\n"; + std::cout << ghost_cache; + std::cout << std::flush; + + ghost_cache.access(9, AccessMode::AS_HIT); + std::cout << "Expect: Boundaries: [8, 1, 6]; Stat: [1/11, 1/11, 2/11]\n"; + std::cout << ghost_cache; + std::cout << std::flush; + + ghost_cache.access(1, AccessMode::AS_MISS); + std::cout << "Expect: Boundaries: [9, 4, 6]; Stat: [1/12, 1/12, 2/12]\n"; + std::cout << ghost_cache; + std::cout << std::flush; } void bench1() {