Skip to content

Commit

Permalink
Merge pull request #148 from comparch-security/support-prefetch
Browse files Browse the repository at this point in the history
Support prefetch
  • Loading branch information
wsong83 authored Sep 13, 2024
2 parents 647926b + e2dbc12 commit 9eefce6
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 154 deletions.
4 changes: 2 additions & 2 deletions cache/cache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ class CacheSkewed : public CacheBase
}
}

virtual void hook_read(uint64_t addr, uint32_t ai, uint32_t s, uint32_t w, bool hit, const CMMetadataBase * meta, const CMDataBase *data, uint64_t *delay) override {
if(ai < P) replacer[ai].access(s, w, true, false);
virtual void hook_read(uint64_t addr, uint32_t ai, uint32_t s, uint32_t w, bool hit, bool prefetch, const CMMetadataBase * meta, const CMDataBase *data, uint64_t *delay) override {
if(ai < P) replacer[ai].access(s, w, true, prefetch);
if constexpr (EnMon || !C_VOID<DLY>) monitors->hook_read(addr, ai, s, w, hit, meta, data, delay);
}

Expand Down
3 changes: 3 additions & 0 deletions cache/coh_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace coh {
const uint32_t evict_act = 2;
const uint32_t writeback_act = 3;
const uint32_t downgrade_act = 4;
const uint32_t prefetch_act = 5;

// message type
constexpr inline bool is_acquire(coh_cmd_t cmd) { return cmd.msg == acquire_msg; }
Expand All @@ -45,10 +46,12 @@ namespace coh {
constexpr inline bool is_writeback(coh_cmd_t cmd) { return cmd.act == writeback_act; }
constexpr inline bool is_downgrade(coh_cmd_t cmd) { return cmd.act == downgrade_act; }
constexpr inline bool is_write(coh_cmd_t cmd) { return cmd.act == fetch_write_act || cmd.act == evict_act || cmd.act == writeback_act; }
constexpr inline bool is_prefetch(coh_cmd_t cmd) { return cmd.act == prefetch_act; }

// generate command
constexpr inline coh_cmd_t cmd_for_read() { return {-1, acquire_msg, fetch_read_act }; }
constexpr inline coh_cmd_t cmd_for_write() { return {-1, acquire_msg, fetch_write_act}; }
constexpr inline coh_cmd_t cmd_for_prefetch() { return {-1, acquire_msg, prefetch_act }; }
constexpr inline coh_cmd_t cmd_for_flush() { return {-1, flush_msg, evict_act }; }
constexpr inline coh_cmd_t cmd_for_writeback() { return {-1, flush_msg, writeback_act }; }
constexpr inline coh_cmd_t cmd_for_release() { return {-1, release_msg, evict_act }; }
Expand Down
126 changes: 71 additions & 55 deletions cache/coherence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class OuterCohPortBase

virtual void acquire_req(uint64_t addr, CMMetadataBase *meta, CMDataBase *data, coh_cmd_t cmd, uint64_t *delay) = 0;
virtual void writeback_req(uint64_t addr, CMMetadataBase *meta, CMDataBase *data, coh_cmd_t cmd, uint64_t *delay) = 0;
virtual void prefetch_req(uint64_t addr, coh_cmd_t cmd, uint64_t *delay) = 0;

// may not implement probe_resp() and finish_req() if the port is uncached
virtual std::pair<bool, bool> probe_resp(uint64_t addr, CMMetadataBase *meta, CMDataBase *data, coh_cmd_t cmd, uint64_t *delay) { return std::make_pair(false,false); }
Expand Down Expand Up @@ -77,6 +78,7 @@ class InnerCohPortBase

virtual void acquire_resp(uint64_t addr, CMDataBase *data_inner, CMMetadataBase *meta_inner, coh_cmd_t outer_cmd, uint64_t *delay) = 0;
virtual void writeback_resp(uint64_t addr, CMDataBase *data_inner, CMMetadataBase *meta_inner, coh_cmd_t outer_cmd, uint64_t *delay) = 0;
virtual void prefetch_resp(uint64_t addr, coh_cmd_t outer_cmd, uint64_t *delay) = 0;

// may not implement probe_req() and finish_resp() if the port is uncached
virtual std::pair<bool,bool> probe_req(uint64_t addr, CMMetadataBase *meta, CMDataBase *data, coh_cmd_t cmd, uint64_t *delay) { return std::make_pair(false,false); }
Expand Down Expand Up @@ -142,6 +144,11 @@ class OuterCohPortUncached : public OuterCohPortBase
Policy::meta_after_writeback(outer_cmd, meta);
}

virtual void prefetch_req(uint64_t addr, coh_cmd_t outer_cmd, uint64_t *delay) override {
outer_cmd.id = coh_id;
coh->prefetch_resp(addr, outer_cmd, delay);
}

virtual void query_loc_req(uint64_t addr, std::list<LocInfo> *locs) override {
coh->query_loc_resp(addr, locs);
}
Expand Down Expand Up @@ -221,7 +228,7 @@ class InnerCohPortUncached : public InnerCohPortBase

if (data_inner && data) data_inner->copy(data);
Policy::meta_after_grant(cmd, meta, meta_inner);
cache->hook_read(addr, ai, s, w, hit, meta, data, delay);
cache->hook_read(addr, ai, s, w, hit, coh::is_prefetch(cmd), meta, data, delay);
finish_record(addr, coh::cmd_for_finish(cmd.id), !hit, meta, ai, s);
if(cmd.id == -1) finish_resp(addr, coh::cmd_for_finish(cmd.id));
}
Expand All @@ -233,6 +240,10 @@ class InnerCohPortUncached : public InnerCohPortBase
write_line(addr, data_inner, meta_inner, cmd, delay);
}

virtual void prefetch_resp(uint64_t addr, coh_cmd_t cmd, uint64_t *delay) override {
prefetch_line(addr, cmd, delay);
}

virtual void query_loc_resp(uint64_t addr, std::list<LocInfo> *locs) override {
outer->query_loc_req(addr, locs);
locs->push_front(cache->query_loc(addr));
Expand All @@ -254,24 +265,26 @@ class InnerCohPortUncached : public InnerCohPortBase
cache->hook_manage(addr, ai, s, w, true, true, writeback.first, meta, data, delay);
}

virtual std::tuple<CMMetadataBase *, CMDataBase *, uint32_t, uint32_t, uint32_t, bool>
access_line(uint64_t addr, coh_cmd_t cmd, uint16_t prio, uint64_t *delay) { // common function for access a line in the cache
virtual std::tuple<bool, CMMetadataBase *, CMDataBase *, uint32_t, uint32_t, uint32_t>
check_hit_or_replace(uint64_t addr, uint16_t prio, bool do_replace, bool prefetch, uint64_t *delay) { // check hit or get a replacement target
uint32_t ai, s, w;
CMMetadataBase *meta;
CMDataBase *data;
CMMetadataBase *meta = nullptr;
CMDataBase *data = nullptr;
bool hit;

if constexpr (EnMT) {
while(true) {
hit = cache->hit(addr, &ai, &s, &w, prio, true);
hit = cache->hit(addr, &ai, &s, &w, prio, !prefetch);
if(hit) {
std::tie(meta, data) = cache->access_line(ai, s, w); meta->lock();
if(!cache->check_mt_state(ai, s, prio) || !meta->match(addr)) { // hitted acquire is intercepted by a probe and even invalidated
meta->unlock(); meta = nullptr; data = nullptr;
cache->reset_mt_state(ai, s, prio);
continue; // redo the hit check
std::tie(meta, data) = cache->access_line(ai, s, w);
if(!prefetch) { // no need to lock for prefetch
meta->lock();
if(!cache->check_mt_state(ai, s, prio) || !meta->match(addr)) { // acquire is intercepted by a probe and even invalidated
meta->unlock(); meta = nullptr; data = nullptr;
cache->reset_mt_state(ai, s, prio);
continue; // redo the hit check
}
}
} else { // miss
} else if(do_replace) { // miss
if(cache->replace(addr, &ai, &s, &w, prio)) { // lock the cache set and get a replacement candidate
std::tie(meta, data) = cache->access_line(ai, s, w);
meta->lock();
Expand All @@ -287,9 +300,15 @@ class InnerCohPortUncached : public InnerCohPortBase
}
} else {
hit = cache->hit(addr, &ai, &s, &w);
if(!hit) cache->replace(addr, &ai, &s, &w, prio);
std::tie(meta, data) = cache->access_line(ai, s, w);
if(!hit && do_replace) cache->replace(addr, &ai, &s, &w, prio);
if(hit || do_replace) std::tie(meta, data) = cache->access_line(ai, s, w);
}
return std::make_tuple(hit, meta, data, ai, s, w);
}

virtual std::tuple<CMMetadataBase *, CMDataBase *, uint32_t, uint32_t, uint32_t, bool>
access_line(uint64_t addr, coh_cmd_t cmd, uint16_t prio, uint64_t *delay) { // common function for access a line in the cache
auto [hit, meta, data, ai, s, w] = check_hit_or_replace(addr, prio, true, false, delay);

if(hit) {
auto sync = Policy::access_need_sync(cmd, meta);
Expand Down Expand Up @@ -318,51 +337,42 @@ class InnerCohPortUncached : public InnerCohPortBase
}

virtual void flush_line(uint64_t addr, coh_cmd_t cmd, uint64_t *delay) {
uint32_t ai, s, w;
CMMetadataBase *meta = nullptr;
CMDataBase *data = nullptr;
bool hit;
if constexpr (!Policy::is_uncached())
outer->writeback_req(addr, nullptr, nullptr, coh::cmd_for_flush(), delay);
else {
auto [hit, meta, data, ai, s, w] = check_hit_or_replace(addr, XactPrio::flush, false, false, delay);
auto [probe, probe_cmd] = Policy::flush_need_sync(cmd, meta);
if(!hit) return;

if constexpr (EnMT) {
while(true) {
hit = cache->hit(addr, &ai, &s, &w, XactPrio::flush, true);
if(hit) {
std::tie(meta, data) = cache->access_line(ai, s, w); meta->lock();
if(!meta->match(addr)) { // cache line is invalidated by transactions with higher priority
meta->unlock(); meta = nullptr; data = nullptr;
cache->reset_mt_state(ai, s, XactPrio::flush); continue; // redo the hit check
}
}
break;
if(probe) {
auto [phit, pwb] = probe_req(addr, meta, data, probe_cmd, delay); // sync if necessary
if(pwb) cache->hook_write(addr, ai, s, w, true, false, meta, data, delay); // a write occurred during the probe
}
} else {
hit = cache->hit(addr, &ai, &s, &w);
if(hit) std::tie(meta, data) = cache->access_line(ai, s, w);
}

auto [flush, probe, probe_cmd] = Policy::flush_need_sync(cmd, meta);
if(!flush) {
// do not handle flush at this level, and send it to the outer cache
outer->writeback_req(addr, nullptr, nullptr, coh::cmd_for_flush(), delay);
return;
}
auto writeback = Policy::writeback_need_writeback(meta);
if(writeback.first) outer->writeback_req(addr, meta, data, writeback.second, delay); // writeback if dirty

if(!hit) return;
Policy::meta_after_flush(cmd, meta, cache);
cache->hook_manage(addr, ai, s, w, hit, coh::is_evict(cmd), writeback.first, meta, data, delay);

if(probe) {
auto [phit, pwb] = probe_req(addr, meta, data, probe_cmd, delay); // sync if necessary
if(pwb) cache->hook_write(addr, ai, s, w, true, false, meta, data, delay); // a write occurred during the probe
if constexpr (EnMT) { meta->unlock(); cache->reset_mt_state(ai, s, XactPrio::flush); }
}

auto writeback = Policy::writeback_need_writeback(meta);
if(writeback.first) outer->writeback_req(addr, meta, data, writeback.second, delay); // writeback if dirty

Policy::meta_after_flush(cmd, meta, cache);
cache->hook_manage(addr, ai, s, w, hit, coh::is_evict(cmd), writeback.first, meta, data, delay);

if constexpr (EnMT) { meta->unlock(); cache->reset_mt_state(ai, s, XactPrio::flush); }
}

virtual void prefetch_line(uint64_t addr, coh_cmd_t cmd, uint64_t *delay) {
if constexpr (!Policy::is_uncached())
outer->prefetch_req(addr, coh::cmd_for_prefetch(), delay);
else {
auto [hit, meta, data, ai, s, w] = check_hit_or_replace(addr, XactPrio::acquire, true, true, delay);
if(!hit) {
if(meta->is_valid()) evict(meta, data, ai, s, w, delay);
outer->acquire_req(addr, meta, data, coh::cmd_for_prefetch(), delay); // fetch the missing block
cache->hook_read(addr, ai, s, w, hit, true, meta, data, delay);
finish_record(addr, coh::cmd_for_finish(-1), !hit, meta, ai, s);
finish_resp(addr, coh::cmd_for_finish(-1));
}
}
}
};

template<template <typename, bool, typename...> class IPUC, typename Policy, bool EnMT, typename... Extra> requires C_DERIVE<IPUC<Policy, EnMT, Extra...>, InnerCohPortBase>
Expand Down Expand Up @@ -424,6 +434,8 @@ class CoreInterfaceBase
virtual void writeback(uint64_t addr, uint64_t *delay) = 0;
// writeback and invalidate all dirty cache blocks, sync with NVM (wbinvd in x86-64)
virtual void writeback_invalidate(uint64_t *delay) = 0;
// prefetch a block
virtual void prefetch(uint64_t addr, uint64_t *delay) = 0;

// flush the whole cache
virtual void flush_cache(uint64_t *delay) = 0;
Expand All @@ -447,7 +459,7 @@ class CoreInterface : public InnerCohPortUncached<Policy, EnMT>, public CoreInte
addr = normalize(addr);
auto cmd = coh::cmd_for_read();
auto [meta, data, ai, s, w, hit] = this->access_line(addr, cmd, XactPrio::acquire, delay);
cache->hook_read(addr, ai, s, w, hit, meta, data, delay);
cache->hook_read(addr, ai, s, w, hit, false, meta, data, delay);
if constexpr (EnMT) { meta->unlock(); cache->reset_mt_state(ai, s, XactPrio::acquire);}
if(!hit) outer->finish_req(addr);
#ifdef CHECK_MULTI
Expand All @@ -470,9 +482,10 @@ class CoreInterface : public InnerCohPortUncached<Policy, EnMT>, public CoreInte
#endif
}

virtual void flush(uint64_t addr, uint64_t *delay) override { addr = normalize(addr); this->flush_line(addr, coh::cmd_for_flush(), delay); }
virtual void writeback(uint64_t addr, uint64_t *delay) override { addr = normalize(addr); this->flush_line(addr, coh::cmd_for_writeback(), delay); }
virtual void flush(uint64_t addr, uint64_t *delay) override { this->flush_line(normalize(addr), coh::cmd_for_flush(), delay); }
virtual void writeback(uint64_t addr, uint64_t *delay) override { this->flush_line(normalize(addr), coh::cmd_for_writeback(), delay); }
virtual void writeback_invalidate(uint64_t *delay) override { assert(nullptr == "Error: L1.writeback_invalidate() is not implemented yet!"); }
virtual void prefetch(uint64_t addr, uint64_t *delay) override { this->prefetch_line(normalize(addr), coh::cmd_for_prefetch(), delay); }

virtual void flush_cache(uint64_t *delay) override {
auto [npar, nset, nway] = cache->size();
Expand Down Expand Up @@ -570,6 +583,9 @@ class SliceDispatcher : public CohMasterBase
virtual void writeback_resp(uint64_t addr, CMDataBase *data, CMMetadataBase *meta_inner, coh_cmd_t cmd, uint64_t *delay) override {
cohm[hasher(addr)]->writeback_resp(addr, data, meta_inner, cmd, delay);
}
virtual void prefetch_resp(uint64_t addr, coh_cmd_t cmd, uint64_t *delay) override {
cohm[hasher(addr)]->prefetch_resp(addr, cmd, delay);
}
virtual void query_loc_resp(uint64_t addr, std::list<LocInfo> *locs) override {
cohm[hasher(addr)]->query_loc_resp(addr, locs);
}
Expand Down
Loading

0 comments on commit 9eefce6

Please sign in to comment.