☰
gem5预取器定制与aarch64 SPEC2006评估实战拆解
2026/10/6 19:18:17 网站建设 项目流程

深入拆解gem5的预取器定制与aarch64下的SPEC2006评估

我这次把gem5缓存预取器研究这件事从头到尾走了一遍,从读源码、改预取逻辑,到在aarch64架构下把SPEC2006跑起来,中间踩了不少坑。这篇文章就把完整的过程、关键参数、源码结构、运行命令、结果分析方式和典型问题都写出来,希望能给你省点时间。

做预取器研究这件事,绕不开两个痛点:一个是要有一套能改、能调、能出统计数据的模拟平台,另一个是要有一组能代表真实负载压力的基准测试程序。gem5恰好把这两件事都覆盖了,而且它对缓存层级、预取器插入点、统计信息的暴露程度都做得比较透明,适合做体系结构方向的验证工作。再加上aarch64架构在移动端和服务器端的权重越来越大,用ARM指令集跑标准负载来评估预取器,在论文和产品预研里都是常见做法。我用的是gem5的SE模式,不需要启动完整操作系统,配合交叉编译出来的SPEC2006二进制,直接加载可执行文件跑,效率和可复现性都不错。

1. 先搞清楚核心问题:为什么盯上prefetcher,以及gem5能帮我们做什么

1.1 硬件预取器到底解决什么问题

现代处理器的计算速度跟内存访问延迟之间的差距,俗称“存储墙”。虽然cache层级(L1、L2、L3)已经挡掉了大量访问延迟,但cache miss一旦发生,去主存拿数据的代价依然是几百个周期。预取器的思路是:在CPU真正发起访问之前,提前把可能用到的数据搬到离CPU更近的cache里,让后续访问直接命中。

但这事没那么简单。预取做得太激进,会污染cache、占用带宽资源,甚至把原本有用的line挤出去;做得太保守,又起不到隐藏延迟的作用。所以评价一个预取器好不好,不能只看命中率,还要看它对整体IPC、带宽开销、cache污染程度的影响。gem5里提供了多种现成预取器实现,也有统计计数器帮你看每一类miss和prefetch的细节,方便论证方案的收益。

很多刚开始接触gem5的人,以为改预取器就是改几个if条件,实际上远不止如此。预取器的触发点、地址计算逻辑、队列管理、与MSHR的交互、丢弃策略,都会直接影响性能表现。gem5把这些环节全部暴露在源码里,你可以按需定制,这也是我选择它而不是其他模拟器的原因。

1.2 gem5在缓存预取研究里的定位

gem5是一个模块化的事件驱动模拟器,CPU模型、缓存模型、内存模型都可以自由替换。针对预取器研究,gem5提供了几个关键接口:缓存侧每个cache对象可以挂载一个prefetcher实例;CPU侧发出的每个请求都会经过缓存标签查找流程,预取器在miss或响应阶段得到调用机会;系统级的统计框架会把预取相关事件单独记录。

相比纯数学建模,gem5能提供更细粒度的时序反馈。比如,一个L2预取器命中时节省了多少cycles,预取请求占用了多少MSHR entry,这些都能在stats输出里看到。相比全系统模拟,SE模式又省去了启动内核、挂载根文件系统的时间开销,可以更快地跑完基准测试。对于prefetcher这种对OS行为不敏感、对访存pattern敏感的研究场景,SE模式是性价比极高的选择。

这里要提醒一句:SE模式下没有虚拟地址到物理地址的完整转换过程,也不模拟页表walk,它使用的是经过简化的地址翻译。因此如果你的预取器依赖物理页边界识别或页表信息,SE模式的结果需要谨慎解释,必要时得切到FS模式验证。

1.3 为什么选择aarch64架构和SPEC2006

先说架构。ARMv8-A(aarch64)是64位ARM指令集,在服务器、移动端、嵌入式领域都有大量应用。很多论文在x86上验证完方案后,也会在ARM上再跑一遍,证明架构无关性。gem5对ARM的支持相当成熟,提供了完整的ISA描述、系统调用模拟(SE模式下针对ARM64的系统调用翻译)以及设备模型,所以选aarch64作为目标架构没有额外的坑。

再说基准测试。SPEC2006虽然比SPEC2017老,但它的可移植性好、交叉编译方法成熟、运行时间可控,在体系结构论文中仍有大量使用。SPEC2006里的mcf、libquantum、milc、soplex等程序,访存行为差异很大,非常适合用来测试预取器在不同访问模式下的表现。特别是mcf,图遍历带来的访存随机性很强,对任何预取器都是个考验;libquantum则有较规则的长流式访问,适合观察顺序预取器的上限。

我最终定的实验矩阵是:aarch64 CPU模型用O3CPU,L1I/L1D各32KB,L2统一cache 256KB,内存用DDR3_1600_8x8模型,预取器分别测试无预取、NextLine、Stride、以及我自己改的一个基于PC局部性的小实验版本。这样既能看到基准结果,也能看出定制预取器的相对提升。

2. 环境搭建与工具链准备

2.1 编译gem5之前先想清楚三件事

第一,源码版本选择。gem5更新速度很快,不同版本对预取器接口、命令行选项、统计输出格式都有差异。我个人用的是gem5 21.2.0.1这个比较稳定的版本,网上资料也多,遇到问题好搜。不建议直接追最新master,除非你特别需要某个新特性。

第二,CPU模型选择。如果目标只是测试预取器对内存系统的影响,并且需要比较准确的时序行为,建议用O3CPU(详细CPU模型)。它模拟了乱序执行、ROB、load/store queue,能真实反映cache miss对流水线的影响。MinorCPU也可以,但行为更偏顺序执行,和真实处理器的差异更大。如果只是快速验证功能,或者跑特别大的SPEC2006输入集,可以用TimingSimpleCPU先跑通流程,再切换到O3CPU做数据采集。

第三,编译优化级别。gem5默认提供几种编译方式:gem5.opt带优化带调试符号、gem5.debug不带优化带完整调试、gem5.fast最优化无调试。预取器研究一般用gem5.opt就够了,运行速度不至于太慢,出错时还能用gdb追。如果实验量很大,可以编译gem5.fast来跑批量实验,但跑之前一定要在opt版本下确认逻辑没问题。

我这次编译ARM版本的命令如下(源码在~/gem5目录下):

cd ~/gem5 scons build/ARM/gem5.opt -j8

这里有个小坑:scons默认会去检测系统里的交叉编译器,如果你机器上装了多个ARM工具链,可能会因为版本不匹配编译失败。最好先设置环境变量指定工具链路径:

export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH scons build/ARM/gem5.opt -j8

如果编译过程中报错找不到aarch64-linux-gnu-g++,基本就是交叉编译器没装或者不在PATH里。

2.2 aarch64交叉编译链的准备

在跑SPEC2006之前,需要先把测试程序编译成aarch64的可执行文件。这个步骤不是直接用系统自带的gcc就能搞定的,必须用交叉编译工具链。推荐用Linaro的aarch64-linux-gnu工具链,或者Ubuntu自带的gcc-aarch64-linux-gnu包。安裝方式:

sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

装完确认一下编译器是否可用:

aarch64-linux-gnu-gcc --version

如果用Linaro工具链,还需要手动指定sysroot和库路径,稍麻烦一点。建议先试Ubuntu官方包,省时间。

2.3 SPEC2006在aarch64下的编译注意事项

SPEC2006提供了基于Makefile的构建系统,理论上你可以用spec01.ic.300的配置文件来指定编译器、flags、目标路径。交叉编译时最核心的修改点是:config文件里将CC、CXX、FC指向aarch64交叉编译器,并去掉所有-i386、-m32这类x86相关的flags。

我为了省事,直接改了spec的config文件,核心部分如下(以gcc43.conf为模板):

CC = aarch64-linux-gnu-gcc CXX = aarch64-linux-gnu-g++ FC = aarch64-linux-gnu-gfortran COPTIMIZE = -O3 -g CXXOPTIMIZE = -O3 -g FOPTIMIZE = -O3 -g

注意有些benchmark需要32位编译或特殊库支持,比如403.gcc它在SPEC2006里是C程序,但构建时需要生成可执行文件再自举编译,如果交叉环境缺库很容易失败。这种情况常见于mcf、omnetpp等需要标准C++库的程序,需要确保aarch64的libstdc++已装好,否则链接阶段会报找不到libstdc++.so.6。

有些benchmark还需要先构建工具(如spec's tools),如果不想折腾,可以跳过工具构建,直接用gem5的-c参数指定spec2006的原始可执行文件,然后在命令行里传benchmark参数。对于mcf、libquantum这类程序,gem5的SE模式完全可以脱离SPEC harness直接加载运行。

编译好的可执行文件建议放在统一目录,例如~/spec2006_aarch64/,然后写个简单的记录文件,标明每个benchmark对应的编译命令和输入参数。这样做批量实验时不会手忙脚乱。

3. 预取器源码结构:从入口到队列

3.1 src/mem/cache/prefetch/目录结构解读

gem5的预取器实现在src/mem/cache/prefetch/目录下。里面有若干个.cc和.hh文件,每个文件对应一种预取策略:

  • base.hh/base.cc:定义预取器基类Prefetcher,包含队列管理、统计变量、触发接口。
  • next_line.cc/next_line.hh:最简单的顺序预取器,当前行miss或access后预取下一行。
  • stride.cc/stride.hh:步长预取器,检测到固定步长访问流后按步长预取。
  • tagged.cc/tagged.hh:基于标签的预取器,维护一个prefetch tag,按历史触发地址再次触发。
  • signature_path.cc/signature_path.hh:签名路径预取器,比较复杂的全局历史+路径匹配方法。
  • access_map_pattern.cc/access_map_pattern.hh等:更高级的基于访问模式映射的预取器。

在研究阶段,多数人会从修改或模仿stride、tagged入手,因为它们结构清晰,改动量小,效果也容易解释。如果你想做一个完全自定义的预取器,建议从next_line.cc复制出一个新文件,改名并修改notifyMiss和notifyFill相关逻辑,然后在SConscript里注册新增文件,再在Cache.py里添加对应的Prefetcher参数选项。

3.2 核心类Prefetcher的调用流程

理解调用流程是改预取器的基础。cache模块在每次访问时会调用prefetcher->notifyAccess或者更具体的notifyMiss/notifyFill接口。以L2 cache为例,CPU请求到达L2后,如果发生miss,cache会调用预取器的notifyMiss;如果一个请求从内存返回并填充到cache line,会触发notifyFill。预取器在这两个回调里收集信息、更新内部数据结构,并通过schedulePrefetch接口想cache提交预取请求。

void Prefetcher::notifyMiss(const PacketPtr &pkt, const PrefetchInfo &pfi) { // 观察访问流,记录PC、地址、偏移等 // 计算预取地址,调用 promote/prefetch 相关接口 } void Prefetcher::notifyFill(const PacketPtr &pkt) { // 根据填充信息更新预取状态,如确认预取是否有效 }

PrefetchInfo里包含了触发地址、PC、cache line的block offset、是否为prefetch请求等信息。自定义预取器时,通常需要在notifyMiss阶段提取PC(pfi.getPC())和地址(pfi.getAddr()),然后通过addr = addr + stride的方式生成预取地址,最后构造Packet并发送。发送预取请求时要设置isPrefetch标志,这样cache不会把它当作正常请求处理,也不会在未命中时触发新的预取,避免递归爆炸。

3.3 队列、MSHR和带宽:改预取器前必须理解的三个概念

很多人改完预取器发现效果不好,问题往往出在“预取请求根本没发出去”或者“发出去了但被丢弃”。gem5里跟预取请求处理相关的三个核心机制是:

  • 预取队列:prefetchQueue保存待发送的预取请求。队列有大小限制,如果满了,新预取请求可能被丢弃或挤掉旧请求。这意味着预取器“想预取”和“真正预取”之间是有差距的。
  • MSHR (Miss Status Holding Register):cache处理未命中请求时,需要分配MSHR entry。预取请求如果拿不到MSHR,就无法访问内存,只能等待或丢弃。当预取器过于激进、同时触发大量预取时,MSHR会成为瓶颈。
  • 总线带宽:预取请求最终要占用内存和cache之间的总线带宽。如果带宽被预取占满,正常请求的延迟会上升,整体性能反而下降。

在分析实验结果时,一定要结合这几个指标看,不要只看cache hit rate。一个很典型的场景是:预取把hit rate提高了,但CPU的IPC反而下降了,原因就是MSHR拥堵严重、正常load被预取请求阻塞了。这类问题在gem5的stats输出里都有对应计数器,比如system.mem_ctrl.dram_io_bw_prefetch、system.cpu.l2cache.mshr_uncountable_load等。

我后来在自定义预取器里加了一个很简单的门控逻辑:当MSHR占用率超过某个阈值时,暂停新预取的提交。这个思路不复杂,但对性能提升非常明显。

4. 在gem5里跑起来SPEC2006

4.1 se.py命令行参数解析,常用配置推荐

gem5自带了一个配置脚本configs/example/se.py,SE模式下直接用它加载可执行程序即可。常用参数包括:

参数作用我的推荐值
-c指定可执行文件路径SPEC2006 benchmark的aarch64版本
-o传递给被测试程序的参数根据benchmark要求设置
--cpu-typeCPU型号O3CPU
--cpu-clockCPU时钟频率2GHz
--num-cpusCPU核心数1(SE模式多核需谨慎)
--caches是否使能cache层级必须使能
--l2cache是否使能L2 cache必须使能
--l1i_sizeL1指令cache大小32kB
--l1d_sizeL1数据cache大小32kB
--l2_sizeL2 cache大小256kB
--prefetcher预取器类型None/NextLine/Stride/ 自定义类名
--mem-type内存模型DDR3_1600_8x8
--mem-size内存大小4GB

4.2 一条完整的运行命令实例

以一个具体的SPEC2006程序mcf为例,它的标准输入是inp.in,输出丢到/dev/null。编译好的aarch64可执行文件放在~/spec2006_aarch64/429.mcf,对应的输入文件也在同一目录。运行的命令如下:

cd ~/gem5 build/ARM/gem5.opt \ configs/example/se.py \ -c ~/spec2006_aarch64/429.mcf \ -o "~/spec2006_aarch64/inp.in" \ --cpu-type=O3CPU \ --cpu-clock=2GHz \ --num-cpus=1 \ --caches \ --l2cache \ --l1i_size=32kB \ --l1d_size=32kB \ --l2_size=256kB \ --prefetcher=NextLine \ --mem-type=DDR3_1600_8x8 \ --mem-size=4GB

运行结束后,gem5会在当前目录下生成m5out/文件夹,里面最重要的文件是stats.txt和config.ini。config.ini会记录所有模拟参数的实际取值,用于确认实验配置没有出错。stats.txt则是所有性能统计数据的汇总。

跑不同预取器时,建议把每次实验的输出目录单独保存,比如:

mkdir -p results/nextline_429.mcf mv m5out out_429_mcf_nextline

这样后面写对比脚本时非常方便。我习惯每次跑完都把config.ini和stats.txt放到同一个实验目录,再另外用一行文本记录命令行,便于复现。

4.3 从stats.txt里读出预取效果

stats.txt的格式是key value,以空格或tab分隔。预取器研究最常看的指标包括:

system.cpu.cpi # 每指令周期数,越低越好 system.cpu.ipc # 每周期指令数 system.l2.overall_hits::total # L2总命中次数 system.l2.overall_misses::total # L2总未命中次数 system.l2.overall_miss_rate::total # L2缺失率 system.l2.prefetcher.num_hits # 预取请求命中次数 system.l2.prefetcher.num_useful # 被确认有效的预取次数 system.l2.prefetcher.num_invalidated # 预取后被无效的行数 system.l2.mshr_uncountable_load # 因MSHR资源不足而无法分配的请求数

对于预取器研究,我建议重点看这几个比例:

  • 预取命中率 =prefetcher.num_hits / prefetcher.num_prefetched
  • 预取有用率 =prefetcher.num_useful / prefetcher.num_hits
  • 预取覆盖率 =prefetcher.num_useful / overall_misses
  • IPC变化比例 =(ipc_prefetch - ipc_noprefetch) / ipc_noprefetch

单独看任何一个指标都容易误判。比如预取命中率很高,说明预取命中了,但如果MPKI(每千条指令的miss数)没有下降,说明这些命中本来也没多大意义,可能只是把原本就会再次访问的数据提前搬进来了。

4.4 不同预取器对比实验设计

做预取器研究时,最忌讳的就是只跑一两个程序就下结论。SPEC2006里有好几类访存特征明显的程序,值得挑选出来组成一个对比集:

Benchmark访存特征适合观察点
429.mcf图遍历、大量随机指针访问预取失败情况、cache抖动
462.libquantum规则长步长流访问stride预取器上限
471.omnetpp对象池访问、有一定局部性预取命中率与带宽开销
401.bzip2压缩算法、随机性较强预取对IPC影响
450.soplex稀疏矩阵计算、混合模式不同预取策略综合对比
470.lbm流体模拟、大数组连续访问流式预取收益

实验时,先跑一遍“无预取”的baseline,然后分别跑各种预取器配置。为了节省时间,每个benchmark可以用--fast-forward跳过初始化阶段,或者用--max-ticks设置模拟上限。不过,如果只看相对趋势,直接跑完整但缩小输入集也是可以的。SPEC2006的test输入集运行时间短,适合冒烟测试;要出最终数据,最好用ref输入集配上合适的--max-ticks。

我实际跑的时候,会先用test输入集把整套流程串起来,确认每个预取器都能正常加载,再用ref输入集跑批量实验。批量脚本可以是一个简单的bash循环,把prefetcher类型和benchmark组合全部跑一遍,每次跑完自动归档结果文件。

5. 常见问题速查与排查实录

5.1 编译阶段的问题

问题1:scons编译失败,报错找不到aarch64交叉编译器

检查是否有aarch64的gcc/g++。如果装了但scons还是找不到,多半是因为PATH没有设置正确,或者工具链名称不是scons默认查找的aarch64-linux-gnu-g++。在scons命令前执行export PATH=...即可。

问题2:自定义预取器文件没有被编译

新增的.cc文件必须注册到src/mem/cache/prefetch/SConscript里。gem5的构建系统不会自动发现新文件,不注册会导致链接阶段报找不到符号。此外,如果改了类的名字,还需要在src/python/m5/objects/Cache.py中添加对应的Prefetcher类型选项,否则命令行传入自定义名称时无法实例化。

问题3:修改预取器后重新编译,改动没有生效

这通常是scons的依赖追踪问题。尝试删除build目录下对应的.o文件,或者在scons命令后加-c先清理再重新构建。不要每次改几个字符就全量编译,建议直接touch修改的文件,scons会重新编译该文件。

5.2 运行阶段的问题

问题4:SE模式加载SPEC2006程序报“cannot load”

原因通常是可执行文件架构不对,或缺少动态链接器。使用file命令确认输出是ELF 64-bit LSB executable, ARM aarch64。如果程序是动态链接的,gem5的SE模式需要能找到对应的/lib/ld-linux-aarch64.so.1。解决办法是:编译SPEC2006时使用-static选项,把程序打成静态可执行文件,这样在SE模式下跑最省心。

问题5:程序运行到一半卡住或报fault

某些benchmark在SE模式下会调用gem5未实现的系统调用,报fatal: syscall XXX unimplemented。这很常见,比如共享内存操作、获取特定系统信息等。最简单的处理是给benchmark换一个小一点的输入,或者对不符合SE模式的系统调用,在src/arch/arm/linux/se_workload.cc里添加对应的模拟处理(这个侵入性较强,不太建议刚开始就这么搞)。实际中,跑SPEC2006的规范输入集,遇到不支持的syscall概率较低。

问题6:预取器没有任何效果

先检查config.ini里是否启用了预取器。如果--prefetcher=NextLine但stats里prefetcher相关计数全为零,可能是命令行参数没生效。注意--prefetcher参数只在使能了对应cache时有效,比如只设置了--l2cache,那么L1预取器不会触发。还要确认是否加在正确层级。L1 prefetcher和L2 prefetcher是独立的,运行se.py时默认只在L2使能预取器。

5.3 结果分析中的坑

问题7:不同跑法之间IPC抖动大

原因可能是模拟器seed、初始状态或者fast-forward位置不同。SE模式下没有OS干扰,理论上可重复性很高。如果还是抖动,检查是否用了多线程(--num-cpus大于1)导致调度不一致。单核SE模式的可复现性还是很稳的。

问题8:stats.txt里的总访问次数不一致

不同预取器会改变miss/hit状态,从而影响后续访问是否继续被统计,所以“baseline”和“prefetch”之间的某些总访问次数可以不相等。比较时用比例而不是绝对值,才更有意义。

问题9:自定义预取器跑出的结果比NextLine还差

不用慌,很多论文里的复杂预取器在某些benchmark上反而差。可能的原因包括:准入策略太激进、队列太小导致有用预取被丢弃、预取请求优先级太低总是排在普通miss后面。逐项排查:先打开--debug-flags=CachePrefetch跑一个小用例,看预取请求是否生成、是否被cache接受、是否被丢弃,基本就能定位。

6. 实操心得与进阶方向

6.1 设计预取器的一些经验

在我折腾gem5预取器的过程中,有几个经验特别想分享。

第一,先建立基线,再谈创新。很多人上来就想写一个复杂的签名预取器,结果调试三天还跑不通。更靠谱的做法是,先跑出无预取、NextLine、Stride三组baseline,观察哪个benchmark的cache miss最多、哪种访问模式最明显,再针对缺口设计新方案。你的新预取器不是越复杂越好,而是要比baseline有明显提升,并且代价可控。

第二,预取距离和预取度是两个敏感参数。预取距离表示当前触发与预取目标地址之间的line数差,预取度表示一次触发最多产生多少个预取请求。gem5的--prefetch-triggered-by、--prefetch-distance等参数可以在命令行直接调,但自定义预取器里通常需要硬编码或用参数变量。建议在预取器里预留可调参数,用命令行传入,方便扫参。

第三,利用debug flag逐条追踪预取流。gem5的--debug-flags=CachePrefetch可以输出每次prefetch的触发、生成、送入cache的过程。这比在代码里到处加printf高效得多。调试时把--debug-start设置到有问题的触发点,只输出那之后的日志,不然全量日志会把磁盘塞满。

第四,小心统计口径。num_useful是指预取行后来被CPU访问且命中的次数,但有的预取行可能在被访问之前就被替换出去或淘汰了。分析时把num_useful和overall_misses一起看,如果num_useful很低但prefetch hits很高,通常表示你的预取器把未来很短时间内的数据提前搬入,对长期IPC帮助有限。

6.2 进一步能往哪个方向扩展

如果这篇文章里提到的内容你已经跑通了,下一步可以考虑这几个方向。

方向一:把预取器从L2扩展到L1和内存控制器级别。gem5支持在L1 data cache上挂预取器,内存控制器侧的prefetch则涉及src/mem/dram_ctrl.cc中的调度策略,改动要比cache侧复杂,但研究价值更高。

方向二:评估预取器对功耗和带宽的影响。gem5的DRAM模型里有功耗统计,可以把预取器实验结果跟system.mem_ctrl.dram_power等指标关联起来,做“性能-功耗”联合分析。

方向三:引入真实trace验证。restore from gem5的SE模式跑完的trace,或者用gem5的--cpu-type=TraceCPU加载外部访问trace。这样你可以在不重新编译SPEC2006的情况下,反复测试预取器在不同应用特征下的表现。

方向四:把预取器学习类方案(比如基于强化学习或签名路径)在gem5里做一个简化版本验证。gem5的signature_path已经提供了基本框架,你可以在此基础上加自己的全局历史表、置信度计数器,这非常贴近近年SPEED、Berti等论文的核心思想。

6.3 最后再分享一个小技巧

批量实验时,我习惯写一个简单的runner脚本,把所有benchmark和prefetcher组合列出来,每次跑完自动归档到results/目录。归档时不只是保存stats.txt,而是把命令行、config.ini、甚至board配置都一起存好。三个月后回来看数据,你不会记得当时跑了什么参数,但归档文件会告诉你一切。

#!/bin/bash for bm in 429.mcf 462.libquantum 470.lbm; do for pf in None NextLine Stride; do echo "Running $bm with $pf" build/ARM/gem5.opt configs/example/se.py \ -c ~/spec2006_aarch64/$bm \ -o "$INPUT_ARGS" \ --cpu-type=O3CPU --caches --l2cache \ --prefetcher=$pf > /dev/null 2>&1 mkdir -p results/${pf}_${bm} cp m5out/stats.txt results/${pf}_${bm}/ cp m5out/config.ini results/${pf}_${bm}/ done done

这样跑完一轮,用个简单的python脚本解析stats.txt,把所有关键指标整理成CSV表格,画图就方便多了。gem5跑big benchmark(特别是O3CPU + SPEC ref输入)时间不短,提前想好实验矩阵、跑之前用test输入集验证一遍,能帮你节省大量时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询