3.23【A】

SimBricks 作为仿真框架,运行入口大概率是可执行的 Python 脚本 / Shell 脚本,优先搜索这类文件

  • 替换模拟器映射 :将 sim.QemuSim 替换为 Gem5 对应的模拟器类 sim.Gem5Sim
  • 适配 Gem5 主机类型 :Gem5 有专属的主机类(Gem5Host),需替换原有的 I40ELinuxHost
  • 补充 Gem5 必要配置:设置 Gem5 的 CPU 类型、内存大小等必填参数(QEMU 可默认,Gem5 必须显式指定)。

System-Host

这个文件(推测是 simbricks/orchestration/system/host/base.py 或类似路径)定义了仿真中「主机」的抽象模型

  • 描述主机的硬件属性(内存、核心数、磁盘);
  • 管理主机上运行的应用(如 Ping、Sleep);
  • 处理主机与外设(如 NIC 网卡)的 PCIe 连接;
  • 生成主机的配置命令(如网卡驱动加载、IP 配置);
  • 支持 JSON 序列化 / 反序列化(用于仿真配置的持久化)

类的继承关系(核心脉络)

  • 底层基类base.Component 是所有仿真组件(主机、NIC、交换机)的根类,提供基础的 ID、系统关联、接口管理能力;

  • 逐层扩展:每个子类在父类基础上增加专属功能(如 Linux 系统特性、特定网卡驱动)。

  • add_app():向主机添加仿真应用(如你之前代码中的 PingClient);

  • connect_pcie_dev():建立主机与 PCIe 设备(如 NIC 网卡)的连接,是主机与外设交互的核心入口;

  • toJSON()/fromJSON():实现主机配置的序列化 / 反序列化(用于仿真配置的保存和加载)。

全系统主机类 FullSystemHost

  • 硬件参数:内存、核心数、CPU 频率(对应真实主机的硬件配置);
  • 磁盘管理:add_disk() 方法添加磁盘镜像(如你代码中的 DistroDiskImage);
  • 异步准备:prepare() 方法异步准备所有磁盘镜像(仿真启动前的前置操作)。

Linux 主机基础类 BaseLinuxHost

  • 应用限定:仅允许添加 BaseLinuxApplication 类型的应用(如 Ping、Sleep);
  • 命令生成:
    • run_cmds():生成主机上运行应用的命令;
    • cleanup_cmds():生成仿真结束后的清理命令;
    • config_str():拼接所有配置命令(启动、应用、清理),最终传递给仿真器;
  • 配置文件:config_files() 支持向仿真主机内挂载额外文件(如驱动文件)。

通用 Linux 主机类 LinuxHost

  • 清理逻辑:cleanup_cmds() 增加 poweroff -f(仿真结束后强制关机);

  • 初始化配置:

    • prepare_pre_cp():设置环境变量、主机名、/etc/hosts 等基础配置;
    • prepare_post_cp():加载驱动、配置网卡(IP、MAC、启动网卡);
  • 网卡配置:自动遍历主机的 PCIe 接口,为连接的 NIC 配置 IP 地址、启动网卡(核心逻辑)。

    遍历主机的PCIe接口,找到连接的NIC网卡

    for host_inf in base.Interface.filter_by_type(self.interfaces(), pcie.PCIeHostInterface):
    inf = host_inf.get_opposing_interface()
    # 配置网卡IP:eth0/eth1...,添加IP地址(如10.0.0.1/24)
    cmds.append(f"ip addr add {com._ip}/24 dev {ifn}")

这部分代码对应你之前脚本中 nic0.add_ipv4("10.0.0.1") 的实际生效逻辑 ------LinuxHost 会自动读取 NIC 的 IP 配置,生成对应的 ip addr add 命令。

针对 Intel I40E 网卡的专用主机类,仅在通用 LinuxHost 基础上增加了 i40e 驱动的自动加载(无需手动配置)。

你之前代码中使用的 host0 = system.I40ELinuxHost(sys) 就是实例化此类,因此主机启动时会自动加载 i40e 驱动,适配 Intel I40eNIC 网卡。

所有仿真组件(主机、NIC、交换机)都通过「接口(Interface)」实现交互add_if() 就是把「接口」绑定到「组件」上的核心方法,是组件能和外部设备通信的前提。

add_if = add interface(添加接口),作用是:

将一个「通信接口对象」(比如这里的 PCIeHostInterface)注册到当前组件(比如主机)中,让组件拥有这个接口,从而具备和外部设备通信的能力。

序列化 / 反序列化的意义

toJSON()/fromJSON() 方法用于将主机配置转换为 JSON 格式,核心用途:

  • 仿真配置的保存:将复杂的主机配置(硬件、应用、驱动)保存为文件;
  • 跨进程 / 节点传输:仿真调度器(Orchestrator)通过 JSON 传递主机配置给仿真器(如 QEMU/Gem5);
  • 仿真回放:加载历史配置,复现相同的仿真场景。

现实中,一台主机可以插多个 PCIe 设备(比如 1 块网卡 + 1 块显卡 + 1 块固态硬盘),对应到仿真中:

  • 每个 PCIe 设备都需要一个独立的「插槽(接口)」;
  • 主机通过 add_if() 管理所有插槽,框架能清晰知道「主机有哪些 PCIe 接口,分别连了什么设备」

Sim

  • sim_base.Simulator:所有仿真器的根类,封装了仿真器的基础属性(可执行文件路径、名称、组件列表);

  • HostSim:主机仿真器的通用抽象,定义了主机仿真器的共性接口(如 supported_image_formatsfull_name);

  • Gem5Sim/QemuSim:具体的仿真器实现,适配各自的命令行参数、磁盘格式、同步逻辑。

  • 继承 sim_base.Simulator,获取仿真器的基础能力(组件管理、ID 生成、JSON 序列化);

  • 定义主机仿真器的通用接口(未实现的抽象方法,由子类实现):

    • supported_image_formats():声明支持的磁盘镜像格式(Gem5 支持 raw,QEMU 支持 raw/qcow2);
    • add():将「主机组件」(如 I40ELinuxHost)绑定到仿真器;
    • full_name():生成仿真器的唯一名称(如 host.Gem5Sim-1);
    • supported_socket_types():声明支持的 socket 类型(默认 CONNECT,用于组件间通信)。
核心方法:run_cmd()(生成 Gem5 运行命令)

这是整个类的核心,负责将「主机配置」转换为 Gem5 的命令行参数,拆解关键逻辑:

① 基础命令拼接

python

运行

复制代码
cmd = f"{inst.env.repo_base(f'{self._executable}.{self._variant}')} --outdir={输出目录} "
cmd += "额外主参数 "
cmd += f" gem5配置脚本路径 --caches --l2cache 缓存参数 --cpu-clock={主机CPU频率} "
  • gem5.opt 执行文件:拼接变体(如 gem5.fast),对应不同编译版本;
  • 配置脚本:sims/external/gem5/configs/simbricks/simbricks.py(SimBricks 定制的 Gem5 配置脚本);
  • 缓存参数:指定 L1/L2 缓存大小、关联度(32kB L1、32MB L2)。

镜像

DistroDiskImage 是 SimBricks 框架中对预打包发行版磁盘镜像 的封装类,其核心逻辑不是 "创建 / 构建镜像",而是定位和验证已存在的预打包镜像文件,为仿真主机提供可挂载的磁盘路径。

初始化(__init__

  • 接收两个关键参数:h(关联的主机实例)、name(镜像名称,如 "base");
  • 定义该镜像支持的格式:raw(原始镜像)、qcow2(QEMU 写时复制镜像);
  • 不实际创建镜像,仅记录镜像名称和支持的格式。

**路径生成(path() 方法)**这是核心方法,作用是根据指定格式,返回镜像文件的实际路径:

复制代码
# 步骤1:通过仿真环境获取基础路径
path = inst.env.hd_path(self.name)  
# 步骤2:根据格式拼接后缀(仅 raw 加后缀,qcow2 不加)
if format == "raw": path += ".raw"  
# 步骤3:验证文件存在,不存在则抛异常
DiskImage.assert_is_file(path)  

磁盘镜像格式

磁盘镜像格式,本质是把物理硬盘 / 分区的全部数据 + 结构,按特定规则打包成的单个文件格式 ------ 就像你把一个文件夹打包成 zip/rar 格式,不同的是,磁盘镜像包是给模拟器(Gem5/QEMU)"识别和使用" 的,模拟器能直接把这个文件当成真实硬盘来读写

  • 真实电脑:硬盘 → 分区 → 系统 / 数据;
  • 模拟器(Gem5/QEMU):磁盘镜像文件(如 disk.raw/disk.qcow2)→ 模拟器解析格式 → 模拟出 "硬盘" 供虚拟机 / 仿真程序使用

不同模拟器只能识别 / 使用特定格式的磁盘镜像文件,超出支持范围的格式会无法加载

Gem5 的核心定位是「微架构仿真」(关注 CPU / 内存的执行细节),而非 "完整虚拟化"------raw 格式最简单,无需复杂的解析逻辑,能让 Gem5 把资源集中在核心仿真功能上;而 qcow2 的快照、压缩等功能对 Gem5 来说是 "冗余" 的,所以不做支持。

QEMU 是「全功能虚拟化工具」(模拟完整的计算机系统),需要兼顾 "兼容性" 和 "实用性":

  • 支持 raw:兼容其他工具(如 Gem5)生成的镜像,方便跨工具复用;
  • 支持 qcow2:满足实际使用需求(比如节省磁盘空间、做快照回滚),是 QEMU 日常使用的主流格式。

假设你要创建一个 "10GB 容量、实际存 2GB 数据" 的镜像:

  • raw 格式:文件大小 = 10GB(不管实际存多少,占满标称空间);
  • qcow2 格式:文件大小 ≈ 2GB(只存实际数据,节省空间);
  • 如果你想在 Gem5 中使用这个镜像:必须转成 raw 格式(否则 Gem5 识别不了);
  • 如果你想在 QEMU 中使用:直接用 qcow2 即可(更省空间),也可以用 raw(兼容但占空间)

模拟器(QEMU/Gem5)给操作系统 / 程序 "造了个假"------ 让它们以为自己在操作物理硬盘,但实际上所有读写指令都被模拟器拦截,转而操作一个普通的镜像文件

模拟器能做到这一点,本质是靠「硬件抽象 + 地址映射 + 指令拦截」

真实硬盘的核心结构是「扇区(Sector)」------ 硬盘被分成一个个固定大小的块(通常 512 字节 / 4KB),所有数据按扇区地址读写;镜像文件(比如 raw 格式)会完全复刻这个结构:

  • raw 格式文件的第 0-511 字节 = 硬盘第 0 扇区(MBR / 分区表);
  • 第 512-1023 字节 = 硬盘第 1 扇区;
  • 以此类推......相当于把硬盘的 "扇区地址" 直接映射成文件的 "字节偏移地址",一一对应。
步骤 2:模拟器拦截所有 "硬盘读写指令"

操作系统 / 程序要操作硬盘时,会通过「CPU 指令 + 硬件寄存器」向硬盘控制器发命令(比如 "读第 100 扇区");模拟器(QEMU/Gem5)作为 "虚拟硬件层",会拦截这些指令:

  • 不把指令发给真实的物理硬盘控制器;
  • 而是解析指令中的 "扇区地址",转换成镜像文件的 "字节偏移"(比如第 100 扇区 = 100×512 = 51200 字节偏移);
  • 然后对镜像文件执行普通的文件读写(读 / 写 51200 字节位置开始的 512 字节)。
步骤 3:返回 "伪装的结果" 给操作系统

模拟器完成文件读写后,会把结果打包成 "硬盘控制器的响应格式",返回给操作系统 / 程序;操作系统完全察觉不到差异 ------ 它以为自己收到的是物理硬盘的响应,实际上是模拟器从镜像文件里读出来的数据。

不同格式的核心区别,只在 "扇区→文件偏移" 的映射逻辑,拦截 / 返回的流程完全一样:

比如同样是 "读第 100 扇区":

  • raw:直接读文件的 100×512=51200 字节位置;
  • qcow2:先读 qcow2 文件里的 "扇区映射表",看第 100 扇区实际存在文件的哪个位置,再读对应位置(如果该扇区没数据,直接返回空,不用占用文件空间)。

脚本

host1(Gem5/QEMU 仿真的 Linux 主机)添加一个后台运行的 Bash 脚本应用 ,作用是在仿真过程中自动收集 host1 的系统 / 网络信息,并把输出保存到主机内的 /tmp/host1_net_check.log 文件中,用于后续验证和调试。

基础结构:system.ScriptApp(host1, script="...", wait=False)

  • system.ScriptApp:SimBricks 提供的 "脚本应用类",用于在仿真主机中执行自定义 Shell 脚本;

  • host1:指定脚本要在哪个主机上运行(这里是 Ping 服务端 host1);

  • script="""...""":要执行的 Bash 脚本内容(多行字符串);

  • wait=False:脚本后台运行 ,不阻塞仿真流程(即使脚本没执行完,仿真也会继续);如果设为 True,仿真会等待脚本执行完毕后再继续。

    #!/bin/bash # 声明脚本用 Bash 解释器执行

    1. 输出分隔符,标记日志开始

    echo "=== Host1 系统信息 ===" >> /tmp/host1_net_check.log

    2. 输出内核版本、CPU 架构等系统信息,追加到日志文件

    uname -a >> /tmp/host1_net_check.log

    3. 输出所有网卡的 IP/MAC 地址、状态等信息,追加到日志文件

    ip addr show >> /tmp/host1_net_check.log

    4. 测试到 host0(10.0.0.1)的连通性(Ping 3 次),追加到日志文件

    2>&1:把错误输出(如 Ping 超时)也重定向到日志文件,避免遗漏报错

    ping -c 3 10.0.0.1 >> /tmp/host1_net_check.log 2>&1

Simple_ping_ns3

  • DistroDiskImage:基础操作系统镜像(如 Ubuntu),提供运行环境;
  • LinuxConfigDiskImage:临时配置盘,用于注入 IP 配置、驱动加载脚本等(无需修改基础镜像)。
  • 场景举例 :你要跑 10 个不同的仿真案例(不同 IP、不同驱动、不同启动脚本),如果只用一个 DistroDiskImage
    • 每次仿真都要修改基础镜像(比如改 /etc/hosts、装驱动、改 IP);
    • 改完后基础镜像被污染,下次跑其他案例时,必须重新制作镜像,否则会出现 "上一次的配置影响本次仿真" 的问题;
  • 双磁盘方案
    • DistroDiskImage 始终保持 "干净的基础系统",10 个案例都复用这一个镜像;
    • LinuxConfigDiskImage 为每个案例单独生成临时配置,仿真结束后自动删除,完全不影响基础镜像

Project

复制代码
from simbricks.orchestration import system  # 系统组件(主机、NIC、交换机)
from simbricks.orchestration import simulation as sim  # 仿真器(QEMU/NS3/NIC)
from simbricks.orchestration.simulation.net import ns3_components  # ns-3 组件(日志级别等)
from simbricks.orchestration import instantiation as inst  # 仿真实例化(控制执行)
from simbricks.orchestration.helpers import simulation as sim_helpers  # 仿真辅助函数(同步控制)

App.py

复制代码
utils_base.IdObj(基础ID类)
    ↓
Application(所有应用的基类)
    ↓
BaseLinuxApplication(Linux主机应用抽象基类)
    ↓
├─ PingClient(Ping客户端)
├─ Sleep(休眠应用)
├─ NetperfServer/NetperfClient(网络性能测试)
└─ IperfTCPServer/IperfUDPServer/IperfTCPClient/IperfUDPClient(带宽测试)

Netperf/Iperf 系列(网络性能测试)

Netperf:测试网络吞吐量、延迟(TCP_RR 模式可测往返延迟);

Iperf:测试 TCP/UDP 带宽(支持多进程、大缓冲区);

核心逻辑:run_cmds() 返回 netserver/netperf/iperf 命令,用于网络性能基准测试

  • 接口标准化 :所有 Linux 应用都通过 run_cmds() 输出要执行的命令,SimBricks 框架会自动将这些命令注入到仿真主机中执行;
  • 可扩展 :新增自定义应用只需继承 BaseLinuxApplication 并实现 run_cmds()
  • 序列化支持 :所有类都实现 toJSON/fromJSON,便于仿真配置的保存和分布式执行

run_cmds 方法不是打印命令 ,而是定义要在模拟节点上真实执行的命令列表

这些命令最终会被 SimBricks 框架注入到模拟的 Linux 主机(Guest OS)中实际运行 ,而非仅打印日志 ------ 你可以把 run_cmds 理解为 "给模拟主机下达的'操作清单'",框架会负责把这些命令送到模拟环境里执行

Instantiation

instantiation" 的意思是 实例化

在编程和计算机科学中,它指的是根据一个类(class)或模板(template)来创建一个具体的、可用的对象(object)或实例(instance)的过程

Orchestration (编排)

在技术领域,"编排"指的是自动化配置、协调和管理计算机系统、中间件及服务的过程。

  • 简单来说,就是指挥和协调多个独立的组件,让它们协同工作来完成一个复杂的任务。
  • 常见的例子有 Kubernetes(用于容器编排)、Terraform(用于基础设施编排)。
2. Instantiation (实例化)

如上所述,这里指的是创建具体实例的动作。在编排的语境下,这通常意味着"启动"或"创建"一个服务、一个虚拟机、一个容器或一个应用程序。

综合理解

因此,orchestration/instantiation/ 这个目录很可能存放的是负责启动和创建服务实例的代码、脚本或配置文件

假设你正在开发一个电商平台,你需要部署一个数据库、一个后端API和一个前端网页。

  • Orchestration (编排):就是整个部署流程,它定义了先部署数据库,等数据库好了再部署后端API,最后部署前端。
  • Instantiation (实例化):就是编排流程中的具体一步,比如"启动一个MySQL数据库容器"或"创建一个API服务器的虚拟机"。

所以,orchestration/instantiation/ 目录下可能就包含了:

  • 用于启动数据库的脚本。
  • 用于创建API服务实例的配置文件。
  • 定义如何从零开始构建一个应用实例的代码。

总而言之,这个目录里的内容是整个自动化流程中,专门负责"从无到有"创建出具体服务实例的那一部分

  • InstantiationEnvironment:管理仿真运行所需的所有路径(工作目录、临时文件、镜像、日志等),是整个仿真的 "文件系统环境";
  • Instantiation:管理单个仿真任务的完整生命周期(环境初始化、碎片分配、套接字 / 代理配置、检查点管理、依赖解析等),是仿真从 "配置" 到 "运行" 的核心桥梁。

hd_path()解析磁盘镜像路径:如果是绝对路径直接用,否则从项目 images/ 目录读取统一管理 "自定义镜像" 和 "内置镜像" 的路径

Instantiation:仿真实例化的 "总控制器"
核心作用

把「仿真配置(Simulation)」转换成「可执行的仿真任务」,核心职责包括:

  • 管理仿真碎片(Fragment):将大型仿真拆分为多个可分布式运行的碎片;
  • 配置套接字 / 代理:连接不同仿真组件(如主机 <-> 网卡、主机 <-> 内存);
  • 检查点管理:支持仿真状态的保存 / 恢复(加速启动);
  • 路径与环境绑定:关联 InstantiationEnvironment
  • 依赖解析:构建仿真组件的启动依赖关系(如先启动网卡,再启动主机)

「命令注入」在 base.py 中的底层支撑:
  1. env 提供了脚本挂载的基础路径(如 tmp_dir/tmp/sim-exp-1/tmp);
  2. fragments 保证包含主机的碎片被正确分配,命令能被解析;
  3. prepare() 清理并创建挂载目录,保证脚本能被正确挂载;
  4. 套接字管理保证容器内的命令能和其他仿真组件通信(如 ping 命令能发送到目标主机)。

简单说:base.py 不直接处理「命令注入」,但它提供了命令执行的底层环境和核心规则 ------ 没有 base.py 管理的路径、套接字、碎片,后续的命令封装和执行都无法实现。

add_app() 只是把应用 "注册" 到主机的列表中,而真正解析、转换、执行这些应用 的逻辑,分散在 Instantiation(实例化)仿真器(如 Gem5Sim/QemuSim) 的代码中,而非 System 类本身

System 类(system/base.py)只是存储所有组件(Host/NIC/Switch)的容器 ,本身不处理应用逻辑;Host 的 applications 列表,是在仿真实例化阶段 被框架解析,最终由对应仿真器(如 Gem5Sim) 转换为可执行的命令 / 脚本,注入到仿真主机中运行。

instantiation = inst_helpers.simple_instantiation(simulation) 是关键入口,该方法会创建 Instantiation 实例(instantiation/base.py),核心作用是:

  1. 遍历 simulation 中的所有组件(Host/NIC/Switch);
  2. 为每个 Host 生成执行上下文(如挂载目录、环境变量、启动脚本);
  3. 调用仿真器(如 Gem5Sim)的 prepare() 方法,处理 Host 的 applications。

Fragment 是 "一组要在同一进程 / 机器上运行的模拟器",fragments 属性通过 setter 严格校验分片的合法性:

组件间通信(如 Host-NIC、Host - 内存)依赖套接字(Socket),Instantiation 负责为每个接口分配套接字路径和类型(LISTEN/CONNECT):

inst = inst_helpers.simple_instantiation(simulation) 为例,完整链路:

  1. 创建 Instantiation :关联你的 simulation(包含 Gem5Sim/Host1);
  2. 设置 Fragmentfragment.add_simulators(*simulation.all_simulators())inst.fragments = [fragment],校验分片合法性;
  3. 绑定环境inst.env = InstantiationEnvironment(workdir, simbricksdir),初始化所有路径

Simulator

  1. Simulator:所有模拟器(如 Gem5Sim/I40eNicSim)的抽象基类,定义了模拟器的通用行为(组件管理、命令生成、套接字处理、生命周期等);
  2. Simulation:仿真实验的总容器,管理所有模拟器实例、组件 - 模拟器映射、通道(Channel)、资源需求等,是连接 "静态配置" 和 "动态运行" 的核心。

简单说:Simulator 是 "单个仿真器" 的模板,Simulation 是 "整个仿真实验" 的管家。

所有具体模拟器都继承此类,封装了模拟器的通用逻辑:

  • 组件管理(添加 / 过滤组件);
  • 命令生成(run_cmd 抽象方法,子类必须实现);
  • 套接字 / 通道处理(通信相关);
  • 生命周期(prepare/cleanup);
  • 资源需求(核心 / 内存);
  • 序列化 / 反序列化(JSON 转换)。
  • simple_simulation 中创建的模拟器,通过 simulation.add_sim(self) 加入 _sim_list
  • 通过 simulator.add(comp)simulation.add_spec_sim_map(comp, sim) 写入 _sys_sim_map
  • 最终 Simulation_sim_list_sys_sim_map 都包含了所有模拟器 / 组件的关联关系

SimBricks 框架中主机模拟器的具体实现层 ,定义了两种主流的主机仿真器(Gem5Sim/QemuSim),均继承自通用的 HostSim 基类,核心职责是:

  1. 实现 Simulator 抽象基类的所有抽象方法(如 run_cmd/supported_socket_types);
  2. 封装 Gem5/QEMU 模拟器的启动参数、资源需求、生命周期逻辑;
  3. 对接 Host 组件的配置(如 CPU 核心数、内存大小、磁盘镜像),生成可直接执行的模拟器启动命令;
  4. 处理 Host 与外设(PCIe/NIC/ 内存)的通信参数(套接字、延迟、同步)。

简单说:这个文件是「通用模拟器基类」到「具体主机模拟器」的落地实现,是指令从 Instantiation 层传递到 "真实模拟器进程" 的最后一环。

Gem5的run_cmd

复制代码
def run_cmd(self, inst: inst_base.Instantiation) -> str:
    # 1. 选择CPU类型(检查点/正常运行)
    cpu_type = self.cpu_type if not inst.create_checkpoint else self.cpu_type_cp

    # 2. 验证:Gem5Sim仅支持1个FullSystemHost
    full_sys_hosts = self.filter_components_by_type(ty=sys_host.BaseLinuxHost)
    if len(full_sys_hosts) != 1:
        raise Exception("Gem5Sim only supports simulating 1 FullSystemHost")
    host_spec = full_sys_hosts[0]  # 获取绑定的Host配置

    # 3. 拼接Gem5启动命令(核心!)
    cmd = f"{inst.env.repo_base(f'{self._executable}.{self._variant}')} --outdir={inst.env.get_simulator_output_dir(sim=self)} "
    cmd += " ".join(self.extra_main_args)
    # 3.1 基础配置:Gem5脚本路径、缓存配置、CPU/系统时钟
    cmd += (
        f" {inst.env.repo_base('sims/external/gem5/configs/simbricks/simbricks.py')} --caches --l2cache "
        "--l1d_size=32kB --l1i_size=32kB --l2_size=32MB "
        "--l1d_assoc=8 --l1i_assoc=8 --l2_assoc=16 "
        f"--cacheline_size=64 --cpu-clock={host_spec.cpu_freq}"
        f" --sys-clock={self._sys_clock} "
        f"--checkpoint-dir={inst.env.cpdir_sim(sim=self)} "
        f"--kernel={inst.env.repo_base('images/vmlinux')} "
    )
    # 3.2 磁盘镜像:拼接Host配置的所有磁盘
    for disk in host_spec.disks:
        cmd += f"--disk-image={disk.path(inst=inst, format='raw')} "
    # 3.3 CPU/内存配置:对接Host的cores/memory属性
    cmd += (
        f"--cpu-type={cpu_type} --mem-size={host_spec.memory}MB "
        f"--num-cpus={host_spec.cores} "
        "--mem-type=DDR4_2400_16x4 "
    )
    # 3.4 内核命令行:传递Host的kcmd_append(如启动脚本路径)
    if host_spec.kcmd_append is not None:
        cmd += f'--command-line-append="{host_spec.kcmd_append}" '
    # 3.5 检查点配置:创建/恢复检查点
    if inst.create_checkpoint:
        cmd += "--max-checkpoints=1 "
    if inst.restore_checkpoint:
        cmd += "-r 1 "

    # 3.6 通信参数:PCIe/内存接口的套接字、延迟、同步
    latency, sync_period, run_sync = sim_base.Simulator.get_unique_latency_period_sync(channels=self.get_channels())
    # PCIe接口(如NIC):拼接CONNECT类型套接字参数
    pci_interfaces = system.Interface.filter_by_type(interfaces=host_spec.interfaces(), ty=sys_pcie.PCIeHostInterface)
    for inf in pci_interfaces:
        socket = inst.get_socket(interface=inf)
        if socket:
            cmd += (
                f"--simbricks-pci=connect:{socket._path}"
                f":latency={latency}ns"
                f":sync_interval={sync_period}ns"
                + (":sync" if run_sync and not inst.create_checkpoint else "")
                + " "
            )
    # 内存接口:同理拼接参数
    # ... 省略内存接口逻辑 ...

    # 3.7 额外配置参数
    cmd += " ".join(self.extra_config_args)
    return cmd

Dummy

Dummy 英文直译是「假的、虚拟的、占位的」,在编程中,DummyXXX 这类命名的类 / 对象,核心作用是:作为 "占位符" 使用,填补某个需要特定类型对象但暂时无法提供真实实现的场景,避免程序因 "缺少对象" 而崩溃。

简单说:DummySimulator 就是一个「假的模拟器」------ 它继承了 Simulator 抽象基类的结构,但没有实现任何实际的模拟逻辑,仅用于兼容 / 容错场景

DummySimulatorSimulator 基类的 "空实现"(也叫「哑实现」):

  • 它满足 Simulator 的类型要求(能被加入 Simulation_sim_list);
  • 但所有关键方法(run_cmd/supported_socket_types)都只抛出异常,不做任何实际操作;
  • 唯一的额外属性 _is_dummy = True 用于标记 "这是一个假模拟器"。

app处理流程

Simulation 是连接 System(静态配置)和 Instantiation(动态执行)的桥梁,它会遍历 System 中的所有 Host,处理其 applications。

  • 把你定义的 Simulation(包含 Host/NIC/Switch/Application 等所有配置)绑定到一个可执行的 Instantiation 实例
  • Instantiation 设置两个通用默认参数(临时文件自动删除、启用快照),仅此而已。

这个方法仅做「实例化 + 默认参数配置」完全不处理 Application、不执行任何仿真逻辑、不解析任何组件 ------ 它只是创建了一个 "空的执行上下文容器",真正的组件 / 应用处理逻辑在调用 Instantiation 实例的后续方法 (如 prepare()/run())时才触发。

simple_instantiation 返回 Instantiation 实例后,框架对 Application 的操作不会自动触发,而是需要显式调用仿真器的 prepare() 方法 (或框架顶层的 run_simulation() 方法),才会走到 Application 解析逻辑。

这行代码是创建具体的模拟器实例,拆解如下:

  • st:是 compmap 映射中的「模拟器类型」(如 Gem5Sim/I40eNicSim/SwitchNet),本质是一个(而非实例);

  • simulation:是当前正在构建的 Simulation 核心对象(包含仿真的全局配置);

  • st(simulation):调用模拟器类的构造函数,传入 simulation 作为参数,创建该模拟器的实例对象

  • simulator = ...:将创建好的模拟器实例赋值给变量,后续用于绑定组件。

  • Host 配置层Sleep 被加入 host1.applications,其 run_cmds 返回 ["sleep infinity"]

  • Instantiation 层inst.prepare() 调用 host1.gen_cmds(),生成包含 sleep infinity 的脚本,路径写入 host1.kcmd_append

  • Gem5Sim 层run_cmd 读取 host1.kcmd_append,将脚本路径嵌入 Gem5 启动命令的 --command-line-append 参数;

  • 执行层Instantiation.execute() 调用 subprocess 执行 Gem5 启动命令;

  • Gem5 内部 :加载内核,执行 kcmd_append 中的脚本,最终运行 sleep infinity

其他

-> 是 Python 3.5+ 引入的函数返回值类型注解(Type Annotation) 语法,它的作用是:明确告诉开发者 / 编辑器,这个函数预期返回什么类型的值(注意:Python 解释器不会强制校验类型,仅做提示和静态检查用)。

简单说:-> 就是给函数的返回值 "贴标签",让代码更易读、易维护,也能让 IDE(如 VS Code/PyCharm)做类型提示和错误检查。

  • -> None:函数没有返回值(执行完只做操作,不 return 任何东西);
  • -> list[str]:返回一个由字符串组成的列表;
  • -> inst_socket.SockType:返回一个自定义的枚举类型(SockType

在 Docker 容器中执行 pip install matplotlib,库会被安装到容器内部的 Python 环境目录(而非宿主机)

复制代码
# 查看Python库安装路径(执行容器内的python)
python -c "import site; print(site.getsitepackages())"

配置层(simulation.py)→ 实例化层(instantiation.py)→ 执行层(sim_processes.py)

相关推荐
jinanwuhuaguo2 小时前
OpenClaw全网使用人群全景深度分析报告
网络·人工智能·网络协议·rpc·openclaw
李白你好2 小时前
Linux 主机安全巡检与应急响应工具
linux·安全
Deitymoon2 小时前
linux——创建进程
linux
忘忧记2 小时前
pytest + YAML + requests`简单实例化
网络·pytest
竹之却3 小时前
如何使用 SakuraFrp 做内网穿透
运维·服务器·网络·frp·内网穿透·sakurafrp
不一样的故事1263 小时前
抓重点、留弹性、重节奏
大数据·网络·人工智能·安全
爱学习的小囧3 小时前
VMware ESXi V7 无 vCenter 虚拟机磁盘缩减攻略:安全释放存储空间(不丢数据)
服务器·网络·windows·安全·esxi·虚拟化
Sgf2273 小时前
第15章 网络编程
开发语言·网络·php
同聘云3 小时前
腾讯云服务器防火墙与网络安全的关系—不可或缺?
服务器·web安全·腾讯云