在长时间运行的 SoC、UVM 或 AMS 仿真中,系统初始化、软件启动和模拟电路稳定可能占据大量时间。如果每个测试都从 time 0 重新执行这些过程,回归和调试会重复消耗大量计算资源。

Xcelium 的 PBSR(Process-Based Save/Restart)提供了另一种方法:在仿真运行到某个时刻后,保存整个仿真进程的运行状态,后续从这个检查点继续,而不必重新执行检查点之前的过程。

PBSR 的核心不是让初始化运行得更快,而是让后续仿真不再重复初始化。

PBSR 保存的是整个仿真进程

Cadence 将 PBSR 描述为一种进程级保存与恢复机制。保存 PBSR checkpoint 时,工具创建的是整个 simulation process state 的磁盘镜像,其中包括:

  • 仿真进程的内存状态;
  • 已分配的 stack 和 heap;
  • 内存中的对象及引用关系;
  • 文件指针和文件状态;
  • Xcelium 数字仿真状态;
  • Spectre AMS Designer 模拟状态;
  • 集成的 C、C++ 和 SystemC 代码;
  • PLI、VPI、VHPI、DPI 等外部模型;
  • HDL 中通过 $save 触发的保存状态。

Cadence 文档说明,restart 时会重新构造内存并恢复内存引用。也就是说,PBSR 并不是要求 Xcelium 逐一理解并序列化每个 C++ 对象,而是恢复包含这些对象的完整进程内存环境。

参考:Spectre AMS Designer and Xcelium Simulator Mixed-Signal User Guide:PBSR Flow

其基本过程可以表示为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
仿真运行到时间 T
        │
        │ PBSR save
        ▼
保存进程内存、stack、heap、文件位置和外部代码状态
        │
        ▼
生成磁盘上的 process checkpoint image
        │
        │ PBSR restart
        ▼
重新构造仿真进程
        │
        ▼
从时间 T 的状态继续运行

为什么传统 Save/Restart 不够?

Xcelium 早期继承的传统 save/restart 机制主要保存 Verilog 和 VHDL 状态。它存在一些明显限制:

  • 不自动保存外部 C 代码状态;
  • 外部模型可能需要通过 PLI、VPI 或 VHPI 自己实现保存;
  • 不能完整处理线程状态和文件 I/O;
  • 某些 system tasks 和复杂集成环境难以支持;
  • 保存通常要求仿真处于适合传统机制处理的 clean point。

后续出现的 hybrid 机制增加了部分 process checkpoint 能力,可以保存一部分内存状态,但仍不能完整保存线程和文件 I/O,并可能存在传统机制与进程机制相互配合的问题。

新的 PBSR 采用更加完整的进程级方法,使大部分集成到仿真进程中的 C 代码不再需要自行保存内部数据结构。

参考:Save/Restart User Guide:Save/Restart Checkpointing with Xcelium

保存机制 主要保存对象 外部 C/SystemC 状态 文件与线程状态
Traditional Verilog、VHDL 和模拟器已知状态 通常需要模型自行处理 支持有限
Hybrid 传统状态加部分进程内存 部分自动保存 仍不完整
Process-based 整个仿真进程状态 大部分可自动保存 PBSR 统一处理支持范围内的状态

PBSR 与 DMTCP 的关系

Cadence 的 checkpoint C/C++ API 将 save/restart 技术区分为:

1
2
3
CDNS_CHECKPOINT_TECH_TRADITIONAL
CDNS_CHECKPOINT_TECH_HYBRID
CDNS_CHECKPOINT_TECH_PROCESS

其中,CDNS_CHECKPOINT_TECH_PROCESS 表示纯进程级方法。

同一套 API 还提供:

1
int cdns_checkpoint_get_dmtcp();

Cadence 文档对该函数的定义是:

1
2
返回 1:当前实现使用 DMTCP
返回 0:当前实现没有使用 DMTCP

由此可以得到两个有明确文档依据的结论:

  1. PBSR 对用户呈现的是 Cadence 的进程级仿真保存与恢复能力。
  2. DMTCP 是否被使用需要在运行环境中查询,并不是所有 PBSR 配置都可以直接认定为 DMTCP。

因此,PBSR 与 DMTCP 不能简单写成等号:

1
2
3
4
5
PBSR
= Cadence 面向 Xcelium/AMS 的完整 Save/Restart 功能

DMTCP
= PBSR 在特定配置中可能使用的进程 checkpoint 实现

Cadence ASK 没有在上述用户指南中承诺所有产品版本、操作系统和运行方式都采用同一个底层实现。除了确认查询接口的语义,不应继续推测具体版本内部如何选择或修改 DMTCP。

参考:Save/Restart User Guide:Additional Considerations

PBSR 如何处理文件?

PBSR 保存时会刷新输出文件,并记录已打开文件的读写位置。

在 restart 时:

  • warm restart 会在原有文件上继续读写;
  • cold restart 可以在新的 invocation directory 中恢复文件;
  • 相对原 invocation directory 的文件会按照相同的相对路径恢复;
  • 位于 invocation directory 之外的文件会被重新安置到 restart 目录下的 ROOT 层次中;
  • 文件的创建状态和读写位置会被恢复。

SHM 和 FSDB 波形数据库也受到支持,使 save 前后的波形能够保持连续。warm restart 时,与 SimVision 或 Verisium Debug 的交互连接也可以重新建立。

哪些对象不能完全自动恢复?

保存进程内存并不意味着可以永久冻结整个外部世界。Cadence 文档列出了需要特别处理的对象,包括:

  • socket;
  • memory-mapped I/O;
  • 非线性文件 I/O;
  • 设备 I/O;
  • inter-process communication;
  • 已关闭的文件;
  • 应用程序启动的其他进程;
  • license server 等外部服务连接。

这些对象可能在 checkpoint 之外发生变化。例如,内存中虽然还存在 license client 对象,但原来的网络连接在 restart 后可能已经失效。

Cadence 因此提供 checkpoint C/C++ API,允许集成组件注册:

1
2
3
4
pre-save
post-save
pre-restart
post-restart

回调可用于重新连接 license server、恢复外部数据库、重新建立通信通道,或者保存 PBSR 核心机制无法自动处理的文件层次。

PBSR 的边界可以概括为:

1
2
3
4
5
进程内部的内存和支持的文件状态
        → PBSR 核心机制处理

外部服务、设备、IPC 和特殊 I/O
        → 通过回调或应用接口处理

Warm restart 与 Cold restart

保存 checkpoint 后,Xcelium 支持 warm restart 和 cold restart。

Warm restart

Warm restart 发生在模拟器仍然运行时,可以使用 Tcl:

1
Xcelium> restart mySavedSnapshot

也可以通过 HDL system task:

$restart("mySavedSnapshot");

Warm restart 的特点包括:

  • 继续使用原来的 simulation directory;
  • 已打开的文件在原位置继续;
  • 交互式 GUI 可以重新连接;
  • 适合反复回到故障发生之前进行调试;
  • 不能改变 simulator invocation options。

Cold restart

Cold restart 会重新启动模拟器:

1
xrun -r mySavedSnapshot

Cold restart 可以在新的 invocation directory 中运行,并允许修改一部分启动选项。Cadence 文档给出的例子包括修改输出日志文件名或 randomization seed。

但并不是所有 simulator options 都可以在 cold restart 时修改。PBSR 仍然恢复原 checkpoint 的设计和进程状态,而不是任意更换整个仿真设置。

参考:Save/Restart User Guide:Restarting the Simulation

PBSR 的三个主要使用场景

Cadence 将 PBSR 的主要 use model 分为 Shared Initialization、Re-debug 和 Recovery。

Shared Initialization

对于包含 SoC boot、firmware initialization 或模拟电路 ramp-up 的测试,可以只执行一次公共初始化:

1
2
3
4
5
6
7
8
公共初始化
    │
    ▼
PBSR checkpoint
    │
    ├── Test A
    ├── Test B
    └── Test C

不同测试从同一个初始化完成状态继续,可以减少重复计算并提高 regression throughput。

Re-debug

在故障发生前保存 checkpoint,后续调试可以反复从该位置恢复:

1
2
3
4
checkpoint
    ├── 开启更多诊断信息后重跑
    ├── 调整允许修改的调试选项后重跑
    └── 重新连接调试器后重跑

这样不必每次都从 time 0 运行到故障附近。

Recovery

长时间仿真可以保存中间 checkpoint。机器、网络或工具发生问题后,可以从最近的保存位置继续,而不必丢弃检查点之前已经完成的仿真。

PBSR checkpoint 与 simulation snapshot

Cadence 文档在不同上下文中都会使用 snapshot,但需要区分两类对象。

Simulation snapshot PBSR checkpoint
由编译和 elaboration 形成 由运行中的仿真形成
描述静态设计结构和可执行模型 描述某一时刻的完整进程状态
通常从 time 0 开始仿真 从保存时刻继续
不包含某次运行到时间 T 的全部动态状态 包含内存、stack、heap、文件位置和外部代码状态
可以被不同测试作为初始可执行模型使用 恢复保存时的具体运行状态

所以,PBSR 文档所说的 snapshot 更准确地理解为:

1
runtime process checkpoint image

而不是 elaboration 生成的 simulation snapshot。

启用 PBSR

Cadence 提供以下选项启用进程级 save/restart:

1
-process_save

该选项可以用于 xrunxmelabxmsim。Cadence 同时建议配合:

1
-64bit

启用后:

  • Tcl save 命令采用 PBSR;
  • Verilog 中的 $save 可以触发 PBSR;
  • 后续可以执行 warm restart 或 cold restart;
  • 同一次运行不能同时使用旧的传统 save/restart 机制。

参考:Save/Restart User Guide:Enabling Process-Based Save/Restart

磁盘空间和压缩开销

PBSR 的代价是保存的数据量明显大于传统 save/restart,因为 checkpoint 包含完整进程内存以及文件 I/O 状态。

Cadence 将 -zlib 扩展到了 PBSR 保存数据,并建议使用:

1
-zlib 1

文档给出的常见压缩比例约为 2:13:1,同时不会引入过大的压缩和解压缩开销。更高的压缩等级可能获得更小的 checkpoint,但会增加保存和恢复时间。

这意味着 PBSR 的收益需要与以下开销一起评估:

  • checkpoint 写入时间;
  • restart 装载时间;
  • checkpoint 文件大小;
  • 文件系统吞吐能力;
  • checkpoint 之前公共初始化的耗时;
  • checkpoint 被多少个后续测试复用。

如果初始化非常短、checkpoint 很大且只复用一次,PBSR 的收益可能有限。反之,如果一次耗时初始化可以被大量测试共享,PBSR 更容易获得明显收益。

结论

PBSR 的本质是进程级 checkpoint/restart:

它保存并重建整个 Xcelium/AMS 仿真进程,而不是只保存 HDL 状态。

它能够覆盖模拟器、UVM testbench、SystemC、C/C++、DPI/PLI/VPI、stack、heap 和文件位置,因此比传统 save/restart 更适合复杂的数字及混合信号验证环境。

DMTCP 与 PBSR 的关系需要保持准确:

Cadence API 可以查询当前 checkpoint 实现是否使用 DMTCP,但 PBSR 是更上层的 Cadence 仿真功能,不能无条件认定所有 PBSR 都等于 DMTCP。

PBSR 提升效率的真正来源也不是加速已经执行的仿真,而是复用已经完成的运行状态:

1
2
3
4
5
运行一次昂贵的初始化
        ↓
保存完整进程 checkpoint
        ↓
让多个测试从该状态继续

这使 PBSR 特别适合 Shared Initialization、Re-debug 和长时间仿真的 Recovery 场景。

参考资料