Skip to content

Commit

Permalink
Merge pull request #156 from comparch-security/dynamic-random
Browse files Browse the repository at this point in the history
Dynamic random
  • Loading branch information
wsong83 authored Sep 21, 2024
2 parents f79f76a + ec099cc commit 35afed0
Show file tree
Hide file tree
Showing 9 changed files with 1,985 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ REGRESSION_TESTS = \
c1-l1 \
c2-l2 c2-l2-mesi c2-l2-exc c2-l2-exc-mi c2-l2-exc-mesi \
c4-l3 c4-l3-exc c4-l3-exc-mesi c4-l3-intel \
c2-l2-mirage
c2-l2-mirage c2-l2-remap

REGRESSION_TESTS_EXE = $(patsubst %, regression/%, $(REGRESSION_TESTS))
REGRESSION_TESTS_LOG = $(patsubst %, regression/%.log, $(REGRESSION_TESTS))
Expand Down
20 changes: 17 additions & 3 deletions cache/cache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ class CacheSkewed : public CacheBase
std::mutex meta_buffer_mutex;
std::condition_variable meta_buffer_cv;

virtual void replace_choose_set(uint64_t addr, uint32_t *ai, uint32_t *s, unsigned int) {
if constexpr (P==1) *ai = 0;
else *ai = ((*loc_random)() % P);
*s = indexer.index(addr, *ai);
}

public:
CacheSkewed(std::string name, unsigned int extra_par = 0, unsigned int extra_way = 0)
: CacheBase(name), meta_buffer_pool(MSHR)
Expand Down Expand Up @@ -273,9 +279,7 @@ class CacheSkewed : public CacheBase
}

virtual bool replace(uint64_t addr, uint32_t *ai, uint32_t *s, uint32_t *w, uint16_t prio, unsigned int genre = 0) override {
if constexpr (P==1) *ai = 0;
else *ai = ((*loc_random)() % P);
*s = indexer.index(addr, *ai);
replace_choose_set(addr, ai, s, genre);
if(EnMT) {
this->set_mt_state(*ai, *s, prio);
// double check the miss status
Expand Down Expand Up @@ -316,6 +320,16 @@ class CacheSkewed : public CacheBase
}
}

__always_inline void swap(uint64_t a_addr, uint64_t b_addr, CMMetadataBase *a_meta, CMMetadataBase *b_meta, CMDataBase *a_data, CMDataBase *b_data) {
auto buffer_meta = meta_copy_buffer();
auto buffer_data = a_data ? data_copy_buffer() : nullptr;
relocate(a_addr, a_meta, buffer_meta, a_data, buffer_data);
relocate(b_addr, b_meta, a_meta, b_data, a_data);
relocate(a_addr, buffer_meta, b_meta, buffer_data, b_data);
meta_return_buffer(buffer_meta);
data_return_buffer(buffer_data);
}

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
212 changes: 212 additions & 0 deletions cache/dynamic_random.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#ifndef CM_CACHE_DYNAMIC_RANDOM_HPP
#define CM_CACHE_DYNAMIC_RANDOM_HPP

#include "cache/coherence.hpp"
#include "util/monitor.hpp"

#define MAGIC_ID_REMAP 2024091300ul

struct RemapHelper {
static const unsigned int replace_for_relocate = 2408200ul;
static const unsigned int replace_during_remap = 2408201ul;
};

// Dynamic-Randomized Skewed Cache
// IW: index width, NW: number of ways, P: number of partitions
// MT: metadata type, DT: data type (void if not in use)
// IDX: indexer type, RPC: replacer type
// EnMon: whether to enable monitoring
template<int IW, int NW, int P, typename MT, typename DT, typename IDX, typename RPC, typename DLY, bool EnMon>
requires C_DERIVE<MT, CMMetadataBase>
&& C_DERIVE_OR_VOID<DT, CMDataBase>
&& C_DERIVE<IDX, IndexSkewed<IW, 6, P>>
&& C_DERIVE_OR_VOID<DLY, DelayBase>
class CacheRemap : public CacheSkewed<IW, NW, P, MT, DT, IDX, RPC, DLY, EnMon>, protected RemapHelper
{
typedef CacheSkewed<IW, NW, P, MT, DT, IDX, RPC, DLY, EnMon> CacheT;

protected:
using CacheT::indexer;
using CacheT::arrays;
using CacheT::replacer;
using CacheT::loc_random;

IDX indexer_next;
std::vector<uint64_t> indexer_seed_next;
std::vector<uint64_t> remap_pointer;
bool remap;

virtual void replace_choose_set(uint64_t addr, uint32_t *ai, uint32_t *s, unsigned int genre) override {
if constexpr (P==1) *ai = 0;
else *ai = ((*loc_random)() % P);
if(0 == genre) *s = indexer.index(addr, *ai);
else if(replace_for_relocate == genre) *s = indexer_next.index(addr, *ai);
else {
assert(replace_during_remap == genre);
assert(0 == "remap in multithread simulation is not supported yet!");
*ai = -1; //force a segment error in release mode
}
}

public:
CacheRemap(std::string name = "", unsigned int extra_par = 0, unsigned int extra_way = 0)
: CacheT(name, extra_par, extra_way), remap(false) {
remap_pointer.resize(P, 0);
indexer_seed_next.resize(P);
std::generate(indexer_seed_next.begin(), indexer_seed_next.end(), cm_get_random_uint64);
indexer_next.seed(indexer_seed_next);
}
virtual ~CacheRemap() {}

void rotate_indexer() {
indexer.seed(indexer_seed_next);
std::generate(indexer_seed_next.begin(), indexer_seed_next.end(), cm_get_random_uint64);
indexer_next.seed(indexer_seed_next);
}

virtual bool hit(uint64_t addr, uint32_t *ai, uint32_t *s, uint32_t *w, uint16_t prio, bool check_and_set) override {
if(!remap) return CacheT::hit(addr, ai, s, w, prio, check_and_set);
for(*ai=0; *ai<P; (*ai)++) {
*s = indexer.index(addr, *ai);
if(*s >= remap_pointer[*ai]){
if (arrays[*ai]->hit(addr, *s, w)) return true;
}
*s = indexer_next.index(addr, *ai);
if (arrays[*ai]->hit(addr, *s, w)) return true;
}
return false;
}

void move_remap_pointer(uint32_t ai) { remap_pointer[ai]++; }

void remap_start() { remap = true; }
void remap_end() {
remap = false;
std::fill(remap_pointer.begin(), remap_pointer.end(), 0);
rotate_indexer();
for(uint32_t ai = 0; ai < P; ai++){
for(uint32_t idx = 0; idx < 1ul<<IW; idx++){
for(uint32_t way = 0; way < NW; way++){
static_cast<MT *>(this->access(ai, idx, way))->to_unrelocated();
}
}
}
}

};

template <typename CT, typename MT, typename Policy, bool EnMT = false>
class InnerCohPortRemapT : public InnerCohPortT<InnerCohPortUncached, Policy, EnMT>, protected RemapHelper
{
typedef InnerCohPortT<InnerCohPortUncached, Policy, EnMT> InnerT;


protected:
using InnerT::cache;
bool remap_flag;

public:
InnerCohPortRemapT() : remap_flag(false){}
void remap(){
auto [p, s, w] = cache->size();
uint32_t P, nset, nway;
std::tie(P, nset, nway) = std::make_tuple(static_cast<uint32_t>(p), static_cast<uint32_t>(s), static_cast<uint32_t>(w));
cache->monitors->pause();
static_cast<CT *>(cache)->remap_start();
for(uint32_t ai = 0; ai < P; ai++){
for(uint32_t idx = 0; idx < nset; idx++){
for(uint32_t way = 0; way < nway; way++){
relocation_chain(ai, idx, way);
}
static_cast<CT *>(cache)->move_remap_pointer(ai);
}
}
static_cast<CT *>(cache)->remap_end();
cache->monitors->resume();
}

virtual void finish_resp(uint64_t addr, coh_cmd_t outer_cmd){
cache->monitors->magic_func(addr, MAGIC_ID_REMAP, &remap_flag);
if(remap_flag) remap();
remap_flag = false;
InnerT::finish_resp(addr, outer_cmd);
}

protected:
void relocation(CMMetadataBase* c_meta, CMDataBase* c_data, uint64_t& c_addr) {
uint32_t new_ai, new_idx, new_way;
cache->replace(c_addr, &new_ai, &new_idx, &new_way, XactPrio::acquire, replace_for_relocate);
auto[m_meta, m_data] = cache->access_line(new_ai, new_idx, new_way);
uint64_t m_addr = m_meta->addr(new_idx);
if (m_meta->is_valid()) {
if (static_cast<MT *>(m_meta)->is_relocated()) this->evict(m_meta, m_data, new_ai, new_idx, new_way, nullptr);
else cache->hook_manage(m_addr, new_ai, new_idx, new_way, true, true, false, m_meta, m_data, nullptr);
}
static_cast<CT *>(cache)->swap(m_addr, c_addr, m_meta, c_meta, m_data, c_data);
cache->hook_read(c_addr, new_ai, new_idx, new_way, false, false, m_meta, m_data, nullptr);
static_cast<MT *>(m_meta)->to_relocated();
c_addr = m_addr;
}

void relocation_chain(uint32_t ai, uint32_t idx, uint32_t way) {
auto[meta, data] = cache->access_line(ai, idx, way);
uint64_t c_addr = meta->addr(idx);
if (!meta->is_valid() || static_cast<MT *>(meta)->is_relocated()) return;
auto c_meta = cache->meta_copy_buffer();
auto c_data = data ? cache->data_copy_buffer() : nullptr;
static_cast<CT *>(cache)->relocate(c_addr, meta, c_meta, data, c_data);
static_cast<MT *>(meta)->to_relocated();
cache->hook_manage(c_addr, ai, idx, way, true, true, false, c_meta, c_data, nullptr);

while(c_meta->is_valid()){
relocation(c_meta, c_data, c_addr);
}
cache->meta_return_buffer(c_meta);
cache->data_return_buffer(c_data);
}
};

// Remap Monitor Base
class RemapperBase : public SimpleAccMonitor
{
protected:
bool remap = false;
bool remap_enable;

public:
RemapperBase(bool remap_enable = true) : SimpleAccMonitor(true), remap_enable(remap_enable) {}

virtual void reset() override {
remap = false;
SimpleAccMonitor::reset();
}

virtual bool magic_func(uint64_t cache_id, uint64_t addr, uint64_t magic_id, void *magic_data) override {
if (magic_id == MAGIC_ID_REMAP) {
if(remap_enable) *static_cast<bool*>(magic_data) |= remap;
remap = false;
return true;
}
return false;
}
};

// Simple Remap Monitor
class SimpleEVRemapper : public RemapperBase
{
protected:
uint64_t period;

public:
SimpleEVRemapper(uint64_t period) : period(period) {}

virtual void invalid(uint64_t cache_id, uint64_t addr, int32_t ai, int32_t s, int32_t w, const CMMetadataBase *meta, const CMDataBase *data) override {
if(!active) return;
cnt_invalid++;
if(cnt_invalid !=0 && (cnt_invalid % period) == 0) {
remap = true;
}
}
};

#endif
16 changes: 5 additions & 11 deletions cache/exclusive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,15 @@ class CacheSkewedExclusive : public CacheSkewed<IW, NW, P, MT, DT, IDX, RPC, DLY
using CacheMonitorSupport::monitors;
protected:
DRPC ext_replacer[P];

public:
CacheSkewedExclusive(std::string name) : CacheT(name, 0, (EnDir ? DW : 0)) {}

virtual bool replace(uint64_t addr, uint32_t *ai, uint32_t *s, uint32_t *w, uint16_t prio, unsigned int genre = 0) override {
if constexpr (!EnDir) CacheT::replace(addr, ai, s, w, prio, 0);
else {
if(0 == genre) CacheT::replace(addr, ai, s, w, prio, 0);
else {
if constexpr (P==1) *ai = 0;
else *ai = ((*loc_random)() % P);
*s = indexer.index(addr, *ai);
ext_replacer[*ai].replace(*s, w);
*w += NW;
}
}
this->replace_choose_set(addr, ai, s, genre);
if constexpr (!EnDir) replacer[*ai].replace(*s, w);
else if(0 == genre) replacer[*ai].replace(*s, w);
else { ext_replacer[*ai].replace(*s, w); *w += NW; }
return true; // ToDo: support multithread
}

Expand Down
30 changes: 14 additions & 16 deletions cache/mirage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ class MirageCache : public CacheSkewed<IW, NW+EW, P, MT, void, MIDX, MRPC, DLY,
DIDX d_indexer; // data index resolver
DRPC d_replacer; // data replacer

virtual void replace_choose_set(uint64_t addr, uint32_t *ai, uint32_t *s, unsigned int genre) override {
int max_free = -1, p = 0;
std::vector<std::pair<uint32_t, uint32_t> > candidates(P);
uint32_t m_s;
for(int i=0; i<P; i++) {
m_s = indexer.index(addr, i);
int free_num = replacer[i].get_free_num(m_s);
if(free_num > max_free) { p = 0; max_free = free_num; }
if(free_num >= max_free)
candidates[p++] = std::make_pair(i, m_s);
}
std::tie(*ai, *s) = candidates[(*loc_random)() % p];
}

public:
MirageCache(std::string name = "") : CacheT(name, 1)
{
Expand Down Expand Up @@ -140,22 +154,6 @@ class MirageCache : public CacheSkewed<IW, NW+EW, P, MT, void, MIDX, MRPC, DLY,
return std::make_pair(d_s, d_w);
}

virtual bool replace(uint64_t addr, uint32_t *ai, uint32_t *s, uint32_t *w, uint16_t prio, unsigned int genre = 0) override {
int max_free = -1, p = 0;
std::vector<std::pair<uint32_t, uint32_t> > candidates(P);
uint32_t m_s;
for(int i=0; i<P; i++) {
m_s = indexer.index(addr, i);
int free_num = replacer[i].get_free_num(m_s);
if(free_num > max_free) { p = 0; max_free = free_num; }
if(free_num >= max_free)
candidates[p++] = std::make_pair(i, m_s);
}
std::tie(*ai, *s) = candidates[(*loc_random)() % p];
replacer[*ai].replace(*s, w);
return true; // ToDo: support multithread
}

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) {
auto [ds, dw] = static_cast<MT *>(this->access(ai, s, w))->pointer();
Expand Down
52 changes: 52 additions & 0 deletions regression/c2-l2-remap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "cache/memory.hpp"
#include "util/cache_type.hpp"
#include "util/regression.hpp"

#define PAddrN 128
#define SAddrN 64
#define NCore 2
#define TestN ((PAddrN + SAddrN) * NCore * 2)

#define L1IW 4
#define L1WN 4

#define L2IW 5
#define L2WN 8

int main() {
using remap_gen = ct::remap::types<L2IW, L2WN, Data64B, ReplaceSRRIP, policy_memory, void, true>;
using policy_l2 = MSIPolicy<false, true, policy_memory>;
using policy_l1d = MSIPolicy<true, false, policy_l2>;
using policy_l1i = MSIPolicy<true, true, policy_l2>;
auto l1d = cache_gen_l1<L1IW, L1WN, Data64B, MetadataBroadcastBase, ReplaceLRU, MSIPolicy, policy_l1d, false, void, true>(NCore, "l1d");
auto core_data = get_l1_core_interface(l1d);
auto l1i = cache_gen_l1<L1IW, L1WN, Data64B, MetadataBroadcastBase, ReplaceLRU, MSIPolicy, policy_l1i, true, void, true>(NCore, "l1i");
auto core_inst = get_l1_core_interface(l1i);
auto l2 = remap_gen::cache_gen_remap(1, "l2")[0];
auto mem = new SimpleMemoryModel<Data64B,void,true>("mem");
SimpleTracer tracer(true);
SimpleEVRemapper Remapper(10);

for(int i=0; i<NCore; i++) {
l1i[i]->outer->connect(l2->inner);
l1d[i]->outer->connect(l2->inner);
l1i[i]->attach_monitor(&tracer);
l1d[i]->attach_monitor(&tracer);
}
l2->outer->connect(mem);

l2->attach_monitor(&tracer);
l2->attach_monitor(&Remapper);
mem->attach_monitor(&tracer);
tracer.start();

RegressionGen<NCore, true, false, PAddrN, SAddrN, Data64B> tgen;
auto rv = tgen.run(TestN, core_inst, core_data);

tracer.stop();
delete_caches(l1d);
delete_caches(l1i);
delete l2;
delete mem;
return rv;
}
Loading

0 comments on commit 35afed0

Please sign in to comment.