Processing math: 100%

2020年9月11日

Cache替换策略

LRU, Least Recently Used, LRU算法根据各block(cache line)使用的情况, 总是选择那个最长时间未被使用的block进行替换。这种策略比较好的反映了程序局部性规律。

gem5中该替换策略的代码:

void
LRURP::invalidate(const std::shared_ptr<ReplacementData>& replacement_data)
const
{
    // Reset last touch timestamp
    std::static_pointer_cast<LRUReplData>(
        replacement_data)->lastTouchTick = Tick(0);
}

void
LRURP::touch(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Update last touch timestamp
    std::static_pointer_cast<LRUReplData>(
        replacement_data)->lastTouchTick = curTick();
}

void
LRURP::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Set last touch timestamp
    std::static_pointer_cast<LRUReplData>(
        replacement_data)->lastTouchTick = curTick();
}

ReplaceableEntry*
LRURP::getVictim(const ReplacementCandidates& candidates) const
{
    // There must be at least one replacement candidate
    assert(candidates.size() > 0);

    // Visit all candidates to find victim
    ReplaceableEntry* victim = candidates[0];
    for (const auto& candidate : candidates) {
        // Update victim entry if necessary
        if (std::static_pointer_cast<LRUReplData>(
                    candidate->replacementData)->lastTouchTick <
                std::static_pointer_cast<LRUReplData>(
                    victim->replacementData)->lastTouchTick) {
            victim = candidate;
        }
    }

    return victim;
}

View Code

MRU(Most Recently Used)和LRU类似,差别在于选择最近被使用的block进行替换。

gem5中该替换策略的代码:

void
MRURP::invalidate(const std::shared_ptr<ReplacementData>& replacement_data)
const
{
    // Reset last touch timestamp
    std::static_pointer_cast<MRUReplData>(
        replacement_data)->lastTouchTick = Tick(0);
}

void
MRURP::touch(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Update last touch timestamp
    std::static_pointer_cast<MRUReplData>(
        replacement_data)->lastTouchTick = curTick();
}

void
MRURP::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Set last touch timestamp
    std::static_pointer_cast<MRUReplData>(
        replacement_data)->lastTouchTick = curTick();
}

ReplaceableEntry*
MRURP::getVictim(const ReplacementCandidates& candidates) const
{
    // There must be at least one replacement candidate
    assert(candidates.size() > 0);

    // Visit all candidates to find victim
    ReplaceableEntry* victim = candidates[0];
    for (const auto& candidate : candidates) {
        std::shared_ptr<MRUReplData> candidate_replacement_data =
            std::static_pointer_cast<MRUReplData>(candidate->replacementData);

        // Stop searching entry if a cache line that doesn't warm up is found.
        if (candidate_replacement_data->lastTouchTick == 0) {
            victim = candidate;
            break;
        } else if (candidate_replacement_data->lastTouchTick >
                std::static_pointer_cast<MRUReplData>(
                    victim->replacementData)->lastTouchTick) {
            victim = candidate;
        }
    }

    return victim;
}

View Code

Random,随机选择一个block进行替换。

gem5中该替换策略的代码:

void
RandomRP::invalidate(const std::shared_ptr<ReplacementData>& replacement_data)
const
{
    // Unprioritize replacement data victimization
    std::static_pointer_cast<RandomReplData>(
        replacement_data)->valid = false;
}

void
RandomRP::touch(const std::shared_ptr<ReplacementData>& replacement_data) const
{
}

void
RandomRP::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Unprioritize replacement data victimization
    std::static_pointer_cast<RandomReplData>(
        replacement_data)->valid = true;
}

ReplaceableEntry*
RandomRP::getVictim(const ReplacementCandidates& candidates) const
{
    // There must be at least one replacement candidate
    assert(candidates.size() > 0);

    // Choose one candidate at random
    ReplaceableEntry* victim = candidates[random_mt.random<unsigned>(0,
                                    candidates.size() - 1)];

    // Visit all candidates to search for an invalid entry. If one is found,
    // its eviction is prioritized
    for (const auto& candidate : candidates) {
        if (!std::static_pointer_cast<RandomReplData>(
                    candidate->replacementData)->valid) {
            victim = candidate;
            break;
        }
    }

View Code

LFU(Least Frequently Used),最近最少被使用次数的block被替换,每个block都有一个引用计数,每次替换该block,都会对该计数加1。

gem5中该替换策略的代码:

void
LFURP::invalidate(const std::shared_ptr<ReplacementData>& replacement_data)
const
{
    // Reset reference count
    std::static_pointer_cast<LFUReplData>(replacement_data)->refCount = 0;
}

void
LFURP::touch(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Update reference count
    std::static_pointer_cast<LFUReplData>(replacement_data)->refCount++;
}

void
LFURP::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Reset reference count
    std::static_pointer_cast<LFUReplData>(replacement_data)->refCount = 1;
}

ReplaceableEntry*
LFURP::getVictim(const ReplacementCandidates& candidates) const
{
    // There must be at least one replacement candidate
    assert(candidates.size() > 0);

    // Visit all candidates to find victim
    ReplaceableEntry* victim = candidates[0];
    for (const auto& candidate : candidates) {
        // Update victim entry if necessary
        if (std::static_pointer_cast<LFUReplData>(
                    candidate->replacementData)->refCount <
                std::static_pointer_cast<LFUReplData>(
                    victim->replacementData)->refCount) {
            victim = candidate;
        }
    }

    return victim;
}
View Code

FIFO(First in First out), 最先使用过的block,最先被替换。

gem5中该替换策略的代码:

void
FIFORP::invalidate(const std::shared_ptr<ReplacementData>& replacement_data)
const
{
    // Reset insertion tick
    std::static_pointer_cast<FIFOReplData>(
        replacement_data)->tickInserted = Tick(0);
}

void
FIFORP::touch(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // A touch does not modify the insertion tick
}

void
FIFORP::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    // Set insertion tick
    std::static_pointer_cast<FIFOReplData>(
        replacement_data)->tickInserted = curTick();
}

ReplaceableEntry*
FIFORP::getVictim(const ReplacementCandidates& candidates) const
{
    // There must be at least one replacement candidate
    assert(candidates.size() > 0);

    // Visit all candidates to find victim
    ReplaceableEntry* victim = candidates[0];
    for (const auto& candidate : candidates) {
        // Update victim entry if necessary
        if (std::static_pointer_cast<FIFOReplData>(
                    candidate->replacementData)->tickInserted <
                std::static_pointer_cast<FIFOReplData>(
                    victim->replacementData)->tickInserted) {
            victim = candidate;
        }
    }

    return victim;
}
View Code

BIP,(Bimodal Insertion Policy)替换策略,是LRU和MRU的结合体,大概率采用MRU替换,小概率采用LRU策略。

gem5中该替换策略的代码

struct BIPRPParams;

class BIPRP : public LRURP
{
  protected:
    /**
     * Bimodal throtle parameter. Value in the range [0,100] used to decide
     * if a new entry is inserted at the MRU or LRU position.
     */
    const unsigned btp;

  public:
    /** Convenience typedef. */
    typedef BIPRPParams Params;

    /**
     * Construct and initiliaze this replacement policy.
     */
    BIPRP(const Params *p);

    /**
     * Destructor.
     */
    ~BIPRP() {}

    /**
     * Reset replacement data for an entry. Used when an entry is inserted.
     * Uses the bimodal throtle parameter to decide whether the new entry
     * should be inserted as MRU, or LRU.
     *
     * @param replacement_data Replacement data to be reset.
     */
    void reset(const std::shared_ptr<ReplacementData>& replacement_data) const
                                                                     override;
};
void
BIPRP::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
    std::shared_ptr<LRUReplData> casted_replacement_data =
        std::static_pointer_cast<LRUReplData>(replacement_data);

    // Entries are inserted as MRU if lower than btp, LRU otherwise
    if (random_mt.random<unsigned>(1, 100) <= btp) {
        casted_replacement_data->lastTouchTick = curTick();
    } else {
        // Make their timestamps as old as possible, so that they become LRU
        casted_replacement_data->lastTouchTick = 1;
    }
}
View Code


NRU(Not Recent Used) 是LRU的一个近似策略,被广泛应用于现代高性能处理器中。应用NRU策略的cache,需要在每个cache block中增加一位标记,该标记(NRU bit)“0”表示最近可能被访问到的,“1”表示最近不能访问到的。

每当一个cache hit,该cache block的NRU bit被设置为“0”表示在最近的将来,该cache block很有可能再被访问到;每当一个cache miss,替换算法会从左至右扫描NRU bit为“1”的block,如果找到则替换出该cache block,并将新插入的cache block 的NRU bit置为“0”,如果没有找到,那么将所有cache block的NRU bit置为“1”,重新从左至右扫描。

STATIC RRIP, 该替换策略是对NRU的扩展,其将NRU bit扩展成M位,当M=1时,该算法蜕化成NRU。而扩展成M位的原因是为了更细粒度的区分cache block,而不是只有两个状态(最近将要访问和最近最远将要访问)。

该算法的描述和NRU相同,每当一个cache hit,该cache block的NRU bit被设置为“0”表示在最近的将来,该cache block很有可能再被访问到;每当一个cache miss,替换算法会从左至右扫描NRU bit为“2^M -1”的block,如果找到则替换出该cache block,并将新插入的cache block 的NRU bit置为“2^M -2”,如果没有找到,那么将所有cache block的NRU bit增加1,重新从左至右扫描。

上面将新插入的cache block设置为“2^M -2”,主要是为了防止那些很久才能被再次使用到的cache block长期占用cache空间, 但这样确实会影响那些空间局部性很好的程序的性能。

在RRIP类的策略中,NRU bit被描述为RRPV(Re- reference Prediction Values),可以理解为当前block被替换出去的可能性,越高越容易被替换出去。


DYNAMIC RRIP(Bimodal RRIP),  对Static RRIP来讲,如果程序的工作集大于cache容量,那么将会频繁的换进换出,造成抖动。为此,Bimodal RRIP提出,对于新插入的cache block,以较大概率设置NRU bits为“2^M -1",同时以较小概率设置为”2^M -2",一次来避免抖动。

那么对于混合的访存序列,应该使用SRRIP还是BRRIP的问题,一种称之为“set Dueling”的技术将两种技术应用到不同的两个cache set上,然后统计两个set上的运行情况(主要是命中率),然后来决断到底使用两种技术中的哪一个,然后将该算法策略部署到其余各个set上。

GEM5中也有BRRIP替换策略的实现。










posted @ 2020-09-11 19:59 迈克老狼2012 阅读(3840) 评论(1) 推荐(0) 编辑

2019年9月2日

E203 itcm

摘要: E203 itcm是64Kb,所以地址总线为16位,2^16=64Kb, 数据线宽度为64 bits(8 bytes),所以address width是16-3=13bit,ram depth 是2^16/8=2^13。 itcm的基地址默认是0x8000_0000。 在目录e200_opensource/riscv-tools/riscv-tests/isa/ge... 阅读全文

posted @ 2019-09-02 14:04 迈克老狼2012 阅读(1470) 评论(1) 推荐(0) 编辑

2019年8月25日

RV32FDQ/RV64RDQ指令集(2)

摘要: 下面我们逐个看下每个指令的细节:fadd.sfadd.s rd, rs1, rs2 //f [rd] = f [rs1] + f [rs2]单精度浮点加(Floating-point Add, Single-Precision). R-type, RV32F and RV64F.把寄存器 f[rs1]和 f[rs2]中的单精度浮点数相加,并将舍入后的和写入 f[rd]。示例:to dofs... 阅读全文

posted @ 2019-08-25 14:25 迈克老狼2012 阅读(2436) 评论(0) 推荐(0) 编辑

RV32FDQ/RV64RDQ指令集(1)

摘要: Risc-V架构定义了可选的单精度浮点指令(F扩展指令集)和双精度浮点指令(D扩展指令集),以及四精度浮点指令集(Q扩展指令集)。Risc-V架构规定:处理器可以选择只实现F扩展指令子集而不支持D扩展指令子集;但是如果支持了D扩展指令子集,则必须支持F扩展指令子集;如果支持了Q扩展指令集,必须支持D扩展指令集。Risc-V架构规定的浮点数符合IEEE754 2008规则,可以从下面的链... 阅读全文

posted @ 2019-08-25 08:41 迈克老狼2012 阅读(2208) 评论(0) 推荐(0) 编辑

2019年8月23日

在vcs中编译及运行测试E203例子

摘要: E203的Makefile默认是调用 iverilog编译rtl,我们可以做如下修改,使其支持vcs编译。1. 首先修改e200_opensource/tb/tb_top.v, 增加dump波形的两行代码,这样如果指定DUMPWAVE不等于0,就会打印dump出波形文件。 initial begin valueplusargs("DUMPWAVE=%d",dumpwave)... 阅读全文

posted @ 2019-08-23 13:00 迈克老狼2012 阅读(3415) 评论(2) 推荐(0) 编辑

2019年8月14日

E203数据冲突处理OITF

摘要: 流水线的数据冲突分为三类:WAR,RAW,WAW https://wenku.baidu.com/view/e066926d48d7c1c708a14508.htmlWAR: write after read 相关性,又称先读后写相关性。比如下面的指令序列,第一条指令会读取x4,第二条指令会写x4。在流水线中,如果第二条指令比第一条指令先写x4,则第一条指令就会读出错误的值... 阅读全文

posted @ 2019-08-14 09:37 迈克老狼2012 阅读(2077) 评论(0) 推荐(0) 编辑

2019年8月13日

Verilog设计Valid-Ready握手协议

摘要: http://ninghechuan.com/2019/01/17/Verilog%E8%AE%BE%E8%AE%A1Valid-Ready%E6%8F%A1%E6%89%8B%E5%8D%8F%E8%AE%AE/ Handshake Protocol握手协议: 为了保证数据传输过程中准确无误,我们需要加上握手信号来控制信号的传输。握手协议的原则是:当Valid和Ready信号同时高有效... 阅读全文

posted @ 2019-08-13 13:42 迈克老狼2012 阅读(9223) 评论(0) 推荐(1) 编辑

E203 CSR rtl实现分析

摘要: CSR状态控制寄存器,每个hart都有自己的CSR。对于每个hart,可以配置的状态寄存器是4k。CSR寄存器的功能见:https://www.cnblogs.com/mikewolf2002/p/11314583.html CSR实现的rtl代码是e203_exu_csr.v,下面我们分析一下代码实现: 输出输入信号如下:module e203_exu_csr( ... 阅读全文

posted @ 2019-08-13 11:33 迈克老狼2012 阅读(1725) 评论(0) 推荐(0) 编辑

2019年8月12日

RiscV汇编介绍(1)-编译过程

摘要: 从c/c++源文件,到可以执行文件,需要以下几个步骤:预处理/编译汇编链接下面我们以hello world程序为例,展示整个编译链接过程。1. 编写hello.c代码#include int main(void){ printf("Hello World!\n"); return 0;}2.使用gcc –E hello.c –o hello.i, 将源文件hello.c... 阅读全文

posted @ 2019-08-12 20:29 迈克老狼2012 阅读(3008) 评论(0) 推荐(0) 编辑

2019年8月8日

RiscV汇编介绍(2)-编译过程

摘要: elf文件全称是Executable and Linkable Format,可执行链接格式,elf文件中除了机器码之外,还有段加载地址,运行入口地址,数据段等。 elf文件格式主要有以下三种:可重定向文件:文件保存着代码和适当的数据,用来和其它的目标文件一起来创建一个可执行文件或者共享目标文件。可执行文件:文件保存着一个用来执行的文件。共享目标文件:即共享库。elf文件详解:... 阅读全文

posted @ 2019-08-08 19:51 迈克老狼2012 阅读(5805) 评论(1) 推荐(0) 编辑

导航

< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示