SMS Prefetcher
主要参考这份代码GEM5/sms.cc at 15447114d16165a2c6e4315e8fcd45138d7dc901 · OpenXiangShan/GEM5 · GitHub
这份代码其实已经不是纯粹的sms, 还杂糅了IPCP的GS, CS。
1. 成员变量
i. active generation table
用region_addr进行寻址
// active generation table
class ACTEntry : public TaggedEntry {
public:
Addr pc;
bool is_secure;
uint64_t region_bits;
bool decr_mode;
uint8_t access_cnt;
uint64_t region_offset;
ACTEntry(const SatCounter8 &conf);
bool in_active_page() {
// FIXME: remove hard-code 12
return access_cnt > 12;
}
};
AssociativeSet<ACTEntry> act;
ii. pattern history table
用pc进行寻址
// pattern history table
class PhtEntry : public TaggedEntry {
public:
std::vector<SatCounter8> hist;
PhtEntry(const size_t sz, const SatCounter8 &conf)
: TaggedEntry(), hist(sz, conf)
{}
};
AssociativeSet<PhtEntry> pht;
2. 成员函数
-
在act中找到对应的act entry
- 如果hit了,更新访问的数据,返回entry
- 如果miss了
- 查看前后两个相邻的region是否是访问密集的entry,如果是,则可以推断该page也是active_page
- evict act entry到pht,并且allocate新的entry。记录pc, region_offset等信息
actLookup
函数
-
如果是active page
Addr pf_tgt_addr = decr ? block_addr - 30 * blkSize : block_addr + 30 * blkSize;
这里+-30提供了足够的lookahead
ACTEntry *act_match_entry = actLookup(pfi, is_active_page);
if (act_match_entry) {
bool decr = act_match_entry->decr_mode;
bool is_cross_region_match = act_match_entry->access_cnt == 0;
if (is_cross_region_match) {
act_match_entry->access_cnt = 1;
}
if (is_active_page) {
// active page
Addr pf_tgt_addr =
decr ? block_addr - 30 * blkSize : block_addr + 30 * blkSize;
Addr pf_tgt_region = regionAddress(pf_tgt_addr);
Addr pf_tgt_offset = regionOffset(pf_tgt_addr);
if (decr) {
for (int i = (int)region_blocks - 1;
i >= pf_tgt_offset && i >= 0; i--) {
Addr cur = pf_tgt_region * region_size + i * blkSize;
addresses.push_back(AddrPriority(cur, i));
}
} else {
for (uint8_t i = 0; i <= pf_tgt_offset; i++) {
Addr cur = pf_tgt_region * region_size + i * blkSize;
addresses.push_back(AddrPriority(cur, region_blocks - i));
}
}
}
}
- 如果不是active page,先看是不是满足stride pattern,这和IPCP的CS是差不多的
void
SMSPrefetcher::strideLookup(const PrefetchInfo &pfi,
std::vector<AddrPriority> &address)
{
Addr lookupAddr = blockAddress(pfi.getAddr());
StrideEntry *entry = stride.findEntry(pfi.getPC(), pfi.isSecure());
if (entry) {
stride.accessEntry(entry);
int64_t new_stride = lookupAddr - entry->last_addr;
bool stride_match = new_stride == entry->stride && new_stride != 0;
if (stride_match) {
entry->conf++;
} else {
if (entry->conf < 2) {
entry->stride = new_stride;
}
entry->conf--;
}
entry->last_addr = lookupAddr;
if (entry->conf >= 2) {
Addr pf_addr = lookupAddr + entry->stride;
address.push_back(AddrPriority(pf_addr, 0));
}
} else {
entry = stride.findVictim(0);
entry->conf.reset();
entry->last_addr = lookupAddr;
entry->stride = 0;
stride.insertEntry(pfi.getPC(), pfi.isSecure(), entry);
}
}
- 如果不是active page, 再看pht
void
SMSPrefetcher::phtLookup(const Base::PrefetchInfo &pfi,
std::vector<AddrPriority> &addresses)
{
Addr pc = pfi.getPC();
Addr vaddr = pfi.getAddr();
Addr blk_addr = blockAddress(vaddr);
Addr region_offset = regionOffset(vaddr);
bool secure = pfi.isSecure();
PhtEntry *pht_entry = pht.findEntry(pc, secure);
if (pht_entry) {
pht.accessEntry(pht_entry);
int priority = 2 * (region_blocks - 1);
// find incr pattern
for (uint8_t i = 0; i < region_blocks - 1; i++) {
if (pht_entry->hist[i + region_blocks - 1].calcSaturation() >
0.5) {
Addr pf_tgt_addr = blk_addr + (i + 1) * blkSize;
addresses.push_back(AddrPriority(pf_tgt_addr, priority--));
}
}
for (int i = region_blocks - 2, j = 1; i >= 0; i--, j++) {
if (pht_entry->hist[i].calcSaturation() > 0.5) {
Addr pf_tgt_addr = blk_addr - j * blkSize;
addresses.push_back(AddrPriority(pf_tgt_addr, priority--));
}
}
}
}