• 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替换策略的实现。










  • 相关阅读:
    Linux下让一个程序开机自动启动
    Heartbeat高可用解决方案
    NFS文件共享
    清除系统日志的三个脚本
    nfs+rsync+inotify实现文件的实时同步
    安装配置rsync服务端
    shell中如何进行算术运算
    linux下查看账号密码的过期时间和设置时间
    配置Nginx作为web server详解
    [LeetCode] 398. Random Pick Index ☆☆☆
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/13653805.html
Copyright © 2020-2023  润新知