如標題所述,這是我修的計算機組織這門課的期末加分題。我就期末為了分數稍微碰一下而已,沒有在這塊鑽研太多,單純紀錄,如有錯誤還請留言糾正。
要改 L3 cache 的直接跳到 5.
我是參考助教的方法安裝並使用 Gem 5,他似乎需要在 Linux 的環境下跑:
1.安裝 VirtualBox 虛擬機 (以下兩個都要下載並安裝)
VirtualBox 7.0.14 platform packages
VirtualBox 7.0.14 Oracle VM VirtualBox Extension Pack
2.下載 Ubuntu 映像檔 (應該只要是Linux就可以,助教用 Ubuntu 我就照做)
- 用映像檔開一個 Ubuntu 虛擬機,記憶體給愈多愈好,Gem5 build 很吃記憶體,CPU核心數能給多的話也能加快速度。硬碟(助教給50GB)也可以給多一點,之後能作為虛擬記憶體(swap)用,我記憶體少所以給個200GB壓壓驚。之後就建立虛擬機然後裝好系統。
- 建議設定讓 Ubuntu 別因閒置自動鎖定,免得 build 到一半自動鎖定?
- 最後參考這篇配多點 swap storage 怕記憶體不夠
3.安裝 Gem5,有任何問題請先參考官方文件
- 開終端機輸入以下指令安裝 Gem5 需要的項目
sudo apt install build-essential git m4 scons zlib1g zlib1g-dev libprotobuf-dev protobuf-compiler libprotoc-dev libgoogle-perftools-dev python3-dev python3 |
- 打以下指令從這裡複製 Gem5 到目錄下
git clone https://github.com/gem5/gem5.git |
- 裝 Gem5 需要的 requirements
sudo pip install install -r requirements.txt |
- 如果像我一樣記憶體很少,建議打以下指令,讓 Ubuntu 不會因 build 時耗太多記憶體把終端機砍掉
sudo systemctl disable --now systemd-oomd |
- 執行以下指令開始 build,j 參數跟CPU核心數有關,詳情請見官方文件
scons build/X86/gem5.opt -j 4 |
然後我只給得出3GB多的記憶體,swap給50GB,build 得有夠久,應該有5、6小時,記憶體夠應該頂多1、2小時
4.開始模擬
- 以下一行很長的指令是我們加分題要測的,使用 se.py 用參數給的 cache 架構執行 Mibench JPEG Encoder ,用其中的 cjpeg 把 input_small.ppm 轉成 output_small_encode.jpeg,系統模擬的紀錄會在 m5out 中,其中 stats.txt 是模擬後的資訊、config.ini應該是一些配置資訊。
以上可見 --l2cache 是啟用 L2 cache 的意思、--l2_size=256kB 就是 L2 cache 的大小,更多資訊請見
或查官方文件。(Mibench JPEG Encoder 是我修的課指定要測的程式,需額外下載)
build/X86/gem5.opt configs/deprecated/example/se.py --cmd=../mibench/consumer/jpeg/jpeg-6a/cjpeg --options="-dct int -progressive -opt -outfile output_small_encode.jpeg" --input=../mibench/consumer/jpeg/input_small.ppm --l1i_size=16kB --l1d_size=64kB --cacheline_size=64 --l1d_assoc=2 --caches --l2_size=256kB --l2cache --cpu-type=TimingSimpleCPU |
build/X86/gem5.opt configs/deprecated/example/se.py --help |
- 如果有要求要記錄 stats.txt 裡某些特定資訊,可以在 Gem5 目錄下用 grep 這個指令取得,因為 stats.txt 裡還蠻多資訊的,每次都進去找有點累。以下為 grep 的使用範例:
grep -E '^system.cpu.icache.overallMisses::total ' m5out/stats.txt grep -E '^system.cpu.icache.overallHits::total ' m5out/stats.txt grep -E '^system.cpu.dcache.overallMisses::total ' m5out/stats.txt grep -E '^system.cpu.dcache.overallHits::total ' m5out/stats.txt grep -E '^system.l2.overallMisses::total ' m5out/stats.txt grep -E '^system.l2.overallHits::total ' m5out/stats.txt grep -E '^system.cpu.numCycles ' m5out/stats.txt |
5.L3 cache 修改
- 如果你此時嘗試用 --l3cache、--l3_size 等參數會發現他找不到,需要修改一些程式碼才行。
- 我參考了以下兩篇文章才改出來,不過以下兩篇跟實際程式碼有些出入,可能是因為程式更新的關係,或許現在我這篇也跟實際程式碼有些出入。
- 私心推薦裝個vscode,在眾多文件中修改比較方便,改錯也能反悔,也可能是我跟vim和nano不熟。
./config/common/Caches.py 新增
class L3Cache(Cache): assoc = 64 tag_latency = 32 data_latency = 32 response_latency =32 mshrs = 32 tgts_per_mshr = 24 write_buffers = 16 |
./config/common/CacheConfig.py 修改
dcache_class, icache_class, l2_cache_class, walk_cache_class = ( core.O3_ARM_v7a_DCache, core.O3_ARM_v7a_ICache, core.O3_ARM_v7aL2, None, ) |
dcache_class, icache_class, l2_cache_class, walk_cache_class,l3_cache_class = ( core.O3_ARM_v7a_DCache, core.O3_ARM_v7a_ICache, core.O3_ARM_v7aL2, None, core.O3_ARM_v7aL3, ) |
./config/common/CacheConfig.py 修改
改成
else: dcache_class, icache_class, l2_cache_class, walk_cache_class = ( L1_DCache, L1_ICache, L2Cache, None, ) |
else: dcache_class, icache_class, l2_cache_class, walk_cache_class,l3_cache_class = ( L1_DCache, L1_ICache, L2Cache, None, L3Cache, ) |
./config/common/CacheConfig.py 修改
if options.l2cache: # Provide a clock for the L2 and the L1-to-L2 bus here as they # are not connected using addTwoLevelCacheHierarchy. Use the # same clock as the CPUs. system.l2 = l2_cache_class( clk_domain=system.cpu_clk_domain, **_get_cache_opts("l2", options) ) system.tol2bus = L2XBar(clk_domain=system.cpu_clk_domain) system.l2.cpu_side = system.tol2bus.mem_side_ports system.l2.mem_side = system.membus.cpu_side_ports |
if options.l2cache and options.l3cache: system.l2 = l2_cache_class(clk_domain=system.cpu_clk_domain, size=options.l2_size, assoc=options.l2_assoc) system.l3 = l3_cache_class(clk_domain=system.cpu_clk_domain, size=options.l3_size, assoc=options.l3_assoc) system.tol2bus = L2XBar(clk_domain = system.cpu_clk_domain) system.tol3bus = L3XBar(clk_domain = system.cpu_clk_domain) system.l2.cpu_side = system.tol2bus.master system.l2.mem_side = system.tol3bus.slave system.l3.cpu_side = system.tol3bus.master system.l3.mem_side = system.membus.slave elif options.l2cache: # Provide a clock for the L2 and the L1-to-L2 bus here as they # are not connected using addTwoLevelCacheHierarchy. Use the # same clock as the CPUs. system.l2 = l2_cache_class( clk_domain=system.cpu_clk_domain, **_get_cache_opts("l2", options) ) system.tol2bus = L2XBar(clk_domain=system.cpu_clk_domain) system.l2.cpu_side = system.tol2bus.mem_side_ports system.l2.mem_side = system.membus.cpu_side_ports |
./src/mem/XBar.py 增加
class L3XBar(CoherentXBar): # 256-bit crossbar by default width = 32 # Assume that most of this is covered by the cache latencies, with # no more than a single pipeline stage for any packet. frontend_latency = 1 forward_latency = 0 response_latency = 1 snoop_response_latency = 1 |
./src/cpu/BaseCPU.py 修改
from m5.objects.XBar import L2XBar |
from m5.objects.XBar import L2XBar, L3XBar |
./src/cpu/BaseCPU.py 在 class BaseCPU 裡增加
def addThreeLevelCacheHierarchy(self, ic, dc, l3c, iwc = None, dwc = None): self.addPrivateSplitL1Caches(ic, dc, iwc, dwc) self.toL3Bus = L3XBar() self.connectCachedPorts(self.toL3Bus) self.l3cache = l3c self.toL2Bus.master = self.l3cache.cpu_side self._cached_ports = ['l3cache.mem_side'] |
./configs/common/Options.py 修改
parser.add_argument("--caches", action="store_true") parser.add_argument("--l2cache", action="store_true") parser.add_argument("--num-dirs", type=int, default=1) |
parser.add_argument("--caches", action="store_true") parser.add_argument("--l2cache", action="store_true") parser.add_argument("--l3cache", action="store_true") parser.add_argument("--num-dirs", type=int, default=1) |
最後再編譯一次即可(他會編譯修改過的地方,不會像第一次如此久)
scons build/X86/gem5.opt -j 4 |
之後就能在 se.py 使用 --l3cache、--l3_size 等參數
結果最後我總成績 110+,溢出超多其實根本不需要做加分題,最後也只給99 :(