gem5の概要
gem5は、コンピュータアーキテクチャの研究・開発に用いられるオープンソースのシステムシミュレータです。主にC++とPythonで構成されており、柔軟なコンポーネント設計により、CPU、メモリ階層、バス構造などを詳細にモデル化することが可能です。
公式サイトおよび主要なドキュメントは以下の通りです:
- 公式サイト: https://www.gem5.org/
- Getting Started: https://www.gem5.org/getting_started/
- 学習ガイド: https://www.gem5.org/documentation/learning_gem5/introduction/
- ドキュメント: https://www.gem5.org/documentation/
gem5の主な特徴:
- モジュール設計により、コンポーネントのカスタマイズや再利用が容易。
- 離散イベントベースのシミュレーション。
- 全システム(FS)モードとシステムコールエミュレーション(SE)モードの両方をサポート。
- 複数のISA(RISC-V、x86、ARMなど)をサポート。
- メモリサブシステムを柔軟に構成可能。
gem5のビルドと実行準備
gem5のソースコードを取得し、対応するアーキテクチャ向けにビルドすることで、実行可能なgem5.optファイルを得ます。このファイルは、シミュレーションを実行するためのエントリポイントです。
基本的なPython構成スクリプトの作成
gem5はPythonスクリプトを使用してシミュレーション環境を構成します。以下は、RISC-Vアーキテクチャ上で単純な「Hello World」プログラムを実行するための設定スクリプトの例です。
import m5
from m5.objects import *
# システム全体を表すオブジェクトを作成
sim_system = System()
# クロックドメインを設定
sim_system.clk_domain = SrcClockDomain()
sim_system.clk_domain.clock = "1GHz"
sim_system.clk_domain.voltage_domain = VoltageDomain()
# メモリ設定
sim_system.mem_mode = "timing"
sim_system.mem_ranges = [AddrRange("512MB")]
# CPUを構成
sim_system.cpu = RiscvTimingSimpleCPU()
# メモリバスを追加
sim_system.membus = SystemXBar()
# CPUのキャッシュポートをメモリバスに接続
sim_system.cpu.icache_port = sim_system.membus.cpu_side_ports
sim_system.cpu.dcache_port = sim_system.membus.cpu_side_ports
# 割り込みコントローラを作成
sim_system.cpu.createInterruptController()
# メモリコントローラを構成
sim_system.mem_ctrl = MemCtrl()
sim_system.mem_ctrl.dram = DDR3_1600_8x8()
sim_system.mem_ctrl.dram.range = sim_system.mem_ranges[0]
sim_system.mem_ctrl.port = sim_system.membus.mem_side_ports
# システムポートを設定
sim_system.system_port = sim_system.membus.cpu_side_ports
# 実行するバイナリを指定
this_path = os.path.dirname(os.path.abspath(__file__))
binary_path = os.path.join(this_path, "../../../tests/test-progs/hello/bin/riscv/linux/hello")
# SEワークロードを設定
sim_system.workload = SEWorkload.init_compatible(binary_path)
# プロセスを構成
test_process = Process()
test_process.cmd = [binary_path]
sim_system.cpu.workload = test_process
sim_system.cpu.createThreads()
# シミュレーションのルートオブジェクトを生成
root = Root(full_system=False, system=sim_system)
m5.instantiate()
# シミュレーションを開始
print("シミュレーションを開始します")
exit_event = m5.simulate()
print(f"シミュレーション終了 @ tick {m5.curTick()} 原因: {exit_event.getCause()}")
スクリプトの構成要素解説
Systemオブジェクト:シミュレーション対象のシステム全体を表します。SrcClockDomain:システム全体のクロック設定を定義します。MemCtrl:メモリコントローラを構成し、DDR3メモリを接続。SystemXBar:CPUとメモリの間の通信を仲介するメモリバス。RiscvTimingSimpleCPU:RISC-V命令セットを実行可能な単純なCPUモデル。SEWorkload:ユーザーモードでの実行バイナリをロード。
SEモードとFSモードの違い
- SE(System Call Emulation)モード:OSの一部機能をエミュレートし、特定のアプリケーションを直接実行。
- FS(Full System)モード:仮想マシンのように、OS全体を含む完全なハードウェア環境をシミュレーション。
シミュレーションの実行と結果
上記スクリプトをhello_sim.pyとして保存し、以下のように実行します:
./build/RISCV/gem5.opt configs/example/hello_sim.py
出力例:
gem5 Simulator System. https://www.gem5.org
gem5 is copyrighted software; use the --copyright option for details.
Global frequency set at 1000000000000 ticks per second
Hello world!
Exiting @ tick 3306500 because exiting with last active thread context