gem5: 实现最后一级缓存LLC分区
2015-08-04 09:30
260 查看
问题:如何实现cpu中最后一级缓存分区呢?如对于LLC 2MB,cache line 64Byte, 32-way,将其分区为16路相连并保持1024 cache sets不变呢?
比如下面的4个set, 8路相连,分区后变成4路有效(标志为1的)的cache。
[thead]
思路:
分区的关键部分包含lru.cc和CacheSet.hh;
lru.cc中关于访问accessBlock()和替换findVictim()的部分需要修改;
accessBlock()控制每次针对LLC的访问仅访问分区内的内容(标志为1的那部分);
findVictim()用于控制LLC发生替换时,替换分区内最后一个块;
增加一个option用于指定分区,如–part=16选项;
方法:
1.修改configs/common/Options.py,增加 –part选项;
2.将分区选项作为缓存的一部分,类似缓存的assoc参数,修改src/mem/cache/BaseCache.py,增加
3.使part在缓存配置中生效,修改configs/common/CacheConfig.py关于一级,二级和三级缓存的设置,如下:
4.为了使part分区对缓存的访问行为产生影响,故需要修改换成替换策略。首先在src/mem/cache/tags/lru.hh中定义part,
其次,修改src/mem/cache/tags/lru.cc,初始化part参数。
再次,修改src/mem/cache/tags/Tags.py中关于LRU类中定义参数part,因为Params *p引用的时候需要该设置。
通过测试,发现cacheset中不能识别part参数,需要修改src/mem/cache/tags/cacheset.hh,增加其定义:
通过测试,发现cacheset中识别的part参数有误,是由于src/mem/cache/tags/lru.cc中未给set[i]赋值。
测试方法备注:
使用下面的调试方法测试,注意l1, l2和l3的相连度都不同,方便调试的时候区分。
5.修改分区的访问控制,访问会调用src/mem/cache/tags/cacheset.hh中的findBlk函数,修改它即可。对于LLC的访问将限定在part内。
6.修改分区的替换方式。src/mem/cache/tags/lru.cc中的findVictim函数。在part分区最后替换。
7.重复上述备注中的测试,Done! 查看part及part分区后的数据是否如预期一样。分区修改完毕。
注意:
需要在三级缓存配置的se.py中添加如下内容,以免以后使用se.py时没有设置part参数而导致LLC自动分区了。
比如下面的4个set, 8路相连,分区后变成4路有效(标志为1的)的cache。
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
分区的关键部分包含lru.cc和CacheSet.hh;
lru.cc中关于访问accessBlock()和替换findVictim()的部分需要修改;
accessBlock()控制每次针对LLC的访问仅访问分区内的内容(标志为1的那部分);
findVictim()用于控制LLC发生替换时,替换分区内最后一个块;
增加一个option用于指定分区,如–part=16选项;
方法:
1.修改configs/common/Options.py,增加 –part选项;
2.将分区选项作为缓存的一部分,类似缓存的assoc参数,修改src/mem/cache/BaseCache.py,增加
part = Param.Int("PartitionSize")
3.使part在缓存配置中生效,修改configs/common/CacheConfig.py关于一级,二级和三级缓存的设置,如下:
# 三级缓存定义中增加part=options.part,指定LLC分区大小 if options.l3cache: system.l3 = l3_cache_class(clk_domain=system.cpu_clk_domain, size=options.l3_size, part=options.part, assoc=options.l3_assoc) # 修改一级缓存的part参数,因为只分区LLC,故part等于l1i_assoc不变 if options.caches: icache = icache_class(size=options.l1i_size, part=options.l1i_assoc, assoc=options.l1i_assoc) dcache = dcache_class(size=options.l1d_size, part=options.l1d_assoc, assoc=options.l1d_assoc) # 修改二级缓存的part参数,因为只分区LLC,故part等于l2_assoc不变 if options.l2cache: system.cpu[i].l2 = l2_cache_class(clk_domain=system.cpu_clk_domain, size=options.l2_size, part=options.l2_assoc, assoc=options.l2_assoc)
4.为了使part分区对缓存的访问行为产生影响,故需要修改换成替换策略。首先在src/mem/cache/tags/lru.hh中定义part,
//在assoc下面加入part定义,必须按照这个顺序,与src/mem/cache/BaseCache.py中的定义顺序需要一致。 protected: /** The associativity of the cache. */ const unsigned assoc; /** The partition size. by sff */ const unsigned part; /** The number of sets in the cache. */ const unsigned numSets;
其次,修改src/mem/cache/tags/lru.cc,初始化part参数。
//增加 part(p->part)的初始化 LRU::LRU(const Params *p) :BaseTags(p), assoc(p->assoc), part(p->part), numSets(p->size / (p->block_size * p->assoc))
再次,修改src/mem/cache/tags/Tags.py中关于LRU类中定义参数part,因为Params *p引用的时候需要该设置。
class LRU(BaseTags): type = 'LRU' cxx_class = 'LRU' cxx_header = "mem/cache/tags/lru.hh" assoc = Param.Int(Parent.assoc, "associativity") part = Param.Int(Parent.part, "partition")
通过测试,发现cacheset中不能识别part参数,需要修改src/mem/cache/tags/cacheset.hh,增加其定义:
template <class Blktype> class CacheSet { public: /** The associativity of this set. */ int assoc; //增加部分 /** The partition size. */ int part;
通过测试,发现cacheset中识别的part参数有误,是由于src/mem/cache/tags/lru.cc中未给set[i]赋值。
//在lru的初始化中添加sets[i].part = part; unsigned blkIndex = 0; // index into blks array for (unsigned i = 0; i < numSets; ++i) { sets[i].assoc = assoc; sets[i].part = part;
测试方法备注:
使用下面的调试方法测试,注意l1, l2和l3的相连度都不同,方便调试的时候区分。
# 修改源代码src中内容后,运行前一定要编译一次,否则修改代码不会生效。 scons -j 8 build/ALPHA/gem5.debug # 开始调试 gdb --args build/ALPHA/gem5.debug configs/example/spec06_l3_se.py --benchmark=bzip2 -n 1 --cpu-type=detailed --cpu-clock=2GHz --caches --l1i_size=32kB --l1i_assoc=4 --l1d_size=32kB --l1d_assoc=8 --l2cache --l2_size=256kB --l2_assoc=16 --l3cache --l3_size=2MB --l3_assoc=32 --part=9 #设置断点 b lru.cc:80 #即LRU初始化代码中 b cacheset.hh:100 #即 way_id = i;中测试part #运行到lru.cc:80时,通过下面的方式鉴别是否设置正确,cacheset也一样 p assoc p part p name() # 如果断点无法调试时,可以设置--debug-flags来生成trace调试
5.修改分区的访问控制,访问会调用src/mem/cache/tags/cacheset.hh中的findBlk函数,修改它即可。对于LLC的访问将限定在part内。
template <class Blktype> Blktype* CacheSet<Blktype>::findBlk(Addr tag, int& way_id) const { /** * Way_id returns the id of the way that matches the block * If no block is found way_id is set to assoc. */ /** * this is the source code. way_id = assoc; for (int i = 0; i < assoc; ++i) { if (blks[i]->tag == tag && blks[i]->isValid()) { way_id = i; return blks[i]; } } */ // modifed for LLC partition. L1 and L2 access normal. way_id = part; for (int i = 0; i < part; ++i) { if (blks[i]->tag == tag && blks[i]->isValid()) { way_id = i; return blks[i]; } } return NULL; }
6.修改分区的替换方式。src/mem/cache/tags/lru.cc中的findVictim函数。在part分区最后替换。
LRU::BlkType* LRU::findVictim(Addr addr, PacketList &writebacks) { unsigned set = extractSet(addr); // grab a replacement candidate //BlkType *blk = sets[set].blks[assoc-1]; this is the source code. BlkType *blk = sets[set].blks[part-1]; // modified if (blk->isValid()) { DPRINTF(CacheRepl, "set %x: selecting blk %x for replacement, blk refCount: %d, drd: %d \n", set, regenerateBlkAddr(blk->tag, set), blk->refCount, blk->drd); } return blk; }
7.重复上述备注中的测试,Done! 查看part及part分区后的数据是否如预期一样。分区修改完毕。
注意:
需要在三级缓存配置的se.py中添加如下内容,以免以后使用se.py时没有设置part参数而导致LLC自动分区了。
# default LLC(L3) partition 0, we should specify this args. Otherwise when we do not want partition, it still executes. by sff if options.part == 0: print "Error: default LLC(L3) partition is 0, we should specify this args '--part=PART'. Otherwise when we do not want partition, it still executes." sys.exit(1)
相关文章推荐
- 创业之初需要的是人而不是钱
- SHell命令总结
- JSP的基本原理
- OKHttp源码解析(三)
- Node.js安装和入门
- 我们无法独立认证自我的存在,如同我们需要镜子才能看清自己的容貌一样,我们需借他人的赞叹而在心理上日益牢固我们的存在感。
- LINUX内核编译步骤详细介绍
- MFC的CFileDialog
- 使用python加密自己的密码
- Ultra-QuickSort(POJ 2299)
- cocos2d-x 在Mac上lua开发环境搭建
- Android开发之如何保证Service不被杀掉(broadcast+system/app)
- AngularJS Tutorial(15)from w3school
- PowerDesigner生成SQL脚本时,对象带有双引号的问题解决
- MyBatis --快速入门
- 编译性语言和解释性语言
- 【面试题】百度
- shell编程之正则表达式
- waterShed-分水岭算法的原理及实现
- 只有静态常量整型数据成员才可以在类中初始化