[代码阅读]gem5中的classic cache 初步(1)

对于classic memory的研究,主要从cache入手;按照常理,首先从config文件入手,发现对于cache的配置,从BaseCache.py文件入手,

然后转到BaseCache.py文件,通过对BaseCache.py的微修改,查看编译的过程,找到BaseCache.py的作用以及与其他文件的关联;


发现:

1.      BaseCache.py主要用于生成params/BaseCache.hh文件;

对于其中Repl对象,我是比较关心的,具体的定义在params/Repl.hh中,该代码也是编译器scons生成的:

===========

//略去宏定义;

class Repl;

#include “params/SimObject.hh”

struct ReplParams : public SimobjectParams{};

===========

通过上面的代码,基本可以看到Repl是个空的对象,基本上不起作用的;通过后续的代码分析,的确可以验证我们当前的这个假设;

 

2.      通过grep命令,可以找到用到”BaseCache.hh”的相关文件有:

a)        mem/cache/base.hh;

b)        mem/cache/prefetch/base.hh;

c)        mem/cache/builder.cc;

 

3.      查看/mem/cache/base.hh文件,使用的方式主要如下:

typedef BaseCacheParams Params;

BaseCache(const Params *p);

 

4.      上面的第二行代码是对象创建函数,查看/mem/cache/base.cc文件,其中的代码如下:

BaseCache::BaseCache(constParams *p)

    : MemObject(p),

      mshrQueue("MSHRs", p->mshrs,4, MSHRQueue_MSHRs),

      writeBuffer("write buffer",p->write_buffers, p->mshrs+1000,

                  MSHRQueue_WriteBuffer),

      blkSize(p->block_size),

      hitLatency(p->latency),

      numTarget(p->tgts_per_mshr),

      forwardSnoops(p->forward_snoops),

      isTopLevel(p->is_top_level),

      blocked(0),

      noTargetMSHR(NULL),

      missCount(p->max_miss_count),

      drainEvent(NULL),

      addrRange(p->addr_range),

      _numCpus(p->num_cpus)

{

}

上述是一个构建函数,初始化参数都来自于BaseCache.hh中的BaseCacheParams对象;

 

5.      Prefetch部分暂时不考虑,我们关注mem/cache/builder.cc文件,这部分的代码完成cache的创建工作,其中值得留意的代码有:


const void *repl= NULL;

验证我们前面的猜想;

 

代码主体:

 

BaseCache *BaseCacheParams::create()

{

    int numSets = size / (assoc * block_size);

    if (subblock_size == 0) {

        subblock_size = block_size;

    }

 

#ifdefined(USE_CACHE_IIC)

    // Build IIC params

    IIC::Params iic_params;

    iic_params.size = size;

    iic_params.numSets = numSets;

    iic_params.blkSize = block_size;

    iic_params.assoc = assoc;

    iic_params.hashDelay = hash_delay;

    iic_params.hitLatency = latency;

    iic_params.rp = repl;

    iic_params.subblockSize = subblock_size;

#else

    constvoid *repl = NULL;

#endif

 

    BUILD_CACHES;

    return NULL;

}

 

 下面的宏完成cache的创建工作:

#defineBUILD_CACHES do {                              \

        if (repl == NULL) {                             \

            if (numSets == 1) {                         \

                BUILD_FALRU_CACHE;                      \

            } else {                                    \

               BUILD_LRU_CACHE;                    \

            }                                           \

        } else {                                        \

            BUILD_IIC_CACHE;                            \

        }                                              \

    } while (0)

 

#if defined(USE_CACHE_LRU)

#define BUILD_LRU_CACHE do {                                            \

        LRU *tags = newLRU(numSets, block_size, assoc, latency);      \

        BUILD_CACHE(LRU,tags);                                        \

    } while (0)

#else

#define BUILD_LRU_CACHE BUILD_CACHE_PANIC("lru cache")

#endif

 

#define BUILD_CACHE(TAGS, tags)                         \

    do {                                               \

        BasePrefetcher*pf;                             \

        if (prefetch_policy ==Enums::tagged) {         \

            pf = newTaggedPrefetcher(this);            \

        }                                              \

        else if(prefetch_policy == Enums::stride) {    \

            pf = newStridePrefetcher(this);            \

        }                                              \

        else if(prefetch_policy == Enums::ghb) {       \

            pf = newGHBPrefetcher(this);               \

        }                                              \

        else {                                          \

            pf = NULL;                                  \

        }                                              \

        Cache<TAGS>*retval =                           \

            newCache<TAGS>(this, tags, pf);            \

        return retval;                                  \

    } while (0)

 

#define BUILD_CACHE_PANIC(x) do {                       \

        panic("%s notcompiled into M5", x);            \

    } while (0)

 

上述代码之中的关键在于如下这句:

        Cache<TAGS> *retval=                           \

            newCache<TAGS>(this, tags, pf);           \

       return retval;

 

6.      这里的cache是一个模板类,将<TAGS>作为参数传递进去后,完成模板的具体化;完成这些操作后,大致就完成cache的创建和操作关联了,

查看上述的代码,一般是采用tag文件夹中的lru.cc,lru.hh来实例化TAG;


### 如何在 Gem5 中实现 Cache 功能 要在 Gem5 模拟器中配置并启用缓存功能,可以通过修改调试标志 `debug-flag` 和调整配置文件来完成。以下是具体方法: #### 修改 Debug Flag 为了观察缓存的行为,在运行模拟之前需要设置合适的调试标志。通过命令行参数指定 `--debug-flags=Cache`,这会激活与缓存相关的调试日志输出[^3]。 ```bash build/X86/gem5.debug --debug-flags=Cache configs/example/se.py ``` 上述命令启用了针对缓存操作的日志记录功能,便于分析缓存命中率、未命中情况以及其他性能指标。 #### 编写或修改配置文件以支持 Cache Gem5 提供了一个简单的 Python 脚本接口用于定义系统的硬件组件及其连接方式。下面是一个基本的示例脚本,展示如何创建一个带有 L1 数据缓存和指令缓存的简单系统[^1]: ```python from m5.objects import * # 创建 CPU 对象 cpu = TimingSimpleCPU() # 定义 L1 缓存对象 class MyL1Cache(Cache): assoc = 2 tag_latency = 2 data_latency = 2 response_latency = 2 mshrs = 10 tgts_per_mshr = 5 l1_data_cache = MyL1Cache(size='32kB', is_writeback=True, write_buffers=16) l1_inst_cache = MyL1Cache(size='32kB', is_writeback=True, write_buffers=16) # 将缓存绑定到 CPU cpu.addTwoLevelCacheHierarchy(l1_i=l1_inst_cache, l1_d=l1_data_cache, l2=None) # 构建内存总线 system = System(cpu=cpu, mem_mode='timing', mem_ranges=[AddrRange('512MB')]) system.membus = SystemXBar() # 连接 CPU 到内存总线 cpu.icache_port = system.membus.cpu_side_ports cpu.dcache_port = system.membus.cpu_side_ports # 添加物理内存设备 system.mem_ctrl = DDR3_1600_x64() system.mem_ctrl.range = system.mem_ranges[0] system.membus.mem_side_ports = system.mem_ctrl.port # 设置根节点 root = Root(full_system=False, system=system) ``` 此代码片段展示了如何构建一个具有两级缓存层次结构的简化模型。其中,`MyL1Cache` 是自定义类继承于标准缓存模板,并设置了关联度 (`assoc`)、延迟 (`tag_latency`, `data_latency`) 等属性。 #### 启动仿真过程 当一切准备就绪后,可以在终端执行如下命令启动仿真实验: ```bash ./build/X86/gem5.opt ./configs/tutorial/simple.py --caches --l1d_size="32KiB" --l1i_size="32KiB" ``` 这里的关键选项 `--caches` 表明我们希望使用默认的缓存配置;而 `--l1d_size` 和 `--l1i_size` 参数分别指定了数据缓存 (L1D) 和指令缓存 (L1I) 的大小。 --- ### 总结 以上介绍了如何利用 Gem5 配置带缓存的功能以及编写相应的 Python 脚本来描述目标架构的设计细节。通过合理设定缓存容量、替换策略和其他重要参数,能够深入研究不同设计决策对于整体系统性能的影响。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值