PrimeTime 跑后端时计算节点 /tmp 被撑满

在多核或分布式后端时序分析场景中,PrimeTime(PT)会在 /tmp 下产生大量临时文件, 轻则拖慢节点,重则导致整个作业因”No space left on device”报错崩溃。

版本参考:Synopsys PrimeTime 2022.x / 2023.x
平台:CentOS 7 / RHEL 8,作业调度:IBM LSF / SGE
官方建议:节点 /tmp 容量 ≥ 物理内存 2 倍(如 RAM 512 GB,则 /tmp 需 ≥ 1 TB)


一、PT 临时文件的来源

PT 运行期间会在本地 /tmp 下写入多类临时文件,来源如下:

来源 说明
寄生参数读取(SPEF/DSPF) PT 为加速解析会将寄生数据缓存到临时文件
多核分析内部通信 multicore 模式下 Master 与 Worker 线程间的共享数据
DMSA Slave 进程 分布式多场景分析(DMSA)中,Slave 在各自节点的 /tmp 写入工作数据
Tcl 脚本临时变量序列化 部分版本会将大型内存对象序列化到磁盘以降低峰值内存

二、与临时目录相关的变量

PT 提供了多个变量来控制临时文件路径,但它们的作用范围和生效条件各不相同:

2.1 pt_tmp_dir(PT 应用变量 / app_var)

1
2
# 在 .synopsys_pt.setup 或 run.tcl 中设置(推荐使用 set_app_var)
set_app_var pt_tmp_dir "/tmpdata/pt_tmp/$env(USER)"
  • 作用:控制 PT 在 high capacity mode 下读取寄生参数时产生的临时文件的存储位置,默认为 /tmp
  • 生效范围:仅在设置该变量的 PT 进程会话(即 Master)中生效。
  • 局限:这是一个 PT 应用变量(app_var),不是 Shell 环境变量,无法通过 export 传递给 Slave 进程。

验证当前值

1
2
3
printvar pt_tmp_dir
# 或
echo $pt_tmp_dir

2.2 multi_core_working_directory(PT 应用变量 / app_var)

1
set_app_var multi_core_working_directory "/tmpdata/pt_mc_work/$env(USER)"
  • 作用:多核分析(set_host_options -num_cores N)时的工作目录,存放 Worker 的日志和交换数据。
  • 默认值:不设置时,默认为启动 PT 时所在的目录(即 pt_shell 被调用时的当前目录)。
  • 要求:必须是所有参与节点均可读写的共享路径(NFS/GPFS/Lustre 等)。

2.3 multi_scenario_working_directory(PT 应用变量 / app_var)

1
set_app_var multi_scenario_working_directory "/tmpdata/pt_dmsa_work/$env(USER)"
  • 作用:DMSA 模式下 Master 与 Slave 之间的共享工作目录,存放各 scenario 的日志和中间数据。
  • 默认值:不设置时,默认为启动 PT 时所在的目录(即 pt_shell 被调用时的当前目录)。
  • 要求:必须是网络可访问的共享路径,且 Master 和所有 Slave 都需有写权限。

2.4 TMPDIR(Shell 环境变量)

1
export TMPDIR=/tmpdata/pt_tmp/$USER
  • 作用:Unix 标准临时目录变量,许多底层库(如 glibc、OpenSSL)会优先读取此变量。
  • 局限:PT 自身对 TMPDIR 的响应行为因版本而异,不能替代 pt_tmp_dir,但同时设置可覆盖底层库的临时文件行为。

三、为什么设置了环境变量还不生效

这是最常见的困惑。以下是已知的失效原因:

3.1 变量类型混淆:PT app_var ≠ Shell 环境变量

pt_tmp_dir 是 PT 的应用变量(app_var),不是 Shell 环境变量。

1
2
3
4
5
6
7
# ❌ 错误:这样设置对 PT 无效
export pt_tmp_dir=/tmpdata/pt_tmp
setenv pt_tmp_dir /tmpdata/pt_tmp

# ✅ 正确:必须在 PT 启动时读取的脚本中用 set_app_var 设置
# .synopsys_pt.setup 或 run.tcl 中:
set_app_var pt_tmp_dir "/tmpdata/pt_tmp"

3.2 Slave 进程继承失效

在 DMSA 分布式模式下,LSF/SGE 将 Slave 作业派发到各计算节点时:

  • Slave 进程独立启动,拥有独立的 PT 会话。
  • Master 中 set_app_var pt_tmp_dir 的设置不会自动传递到 Slave。
  • 每个 Slave 都需要在其启动时的 .synopsys_pt.setup 中读到该设置。

解决方案:将 pt_tmp_dir 写入所有节点都能访问的 .synopsys_pt.setup(通常放在项目共享目录或 $HOME)。

1
2
# 推荐写法(.synopsys_pt.setup)
set_app_var pt_tmp_dir "/tmpdata/pt_scratch/$env(USER)/[exec hostname]"

提示:按主机名划分子目录,避免多节点 Slave 并发写入同一目录产生冲突。

3.3 临时文件来源不止一处

即使正确设置了 pt_tmp_dir,节点 /tmp 仍然可能被写满,原因是:

  • 底层库(如某些第三方 C++ solver)绕过 pt_tmp_dir,直接使用 TMPDIR 或硬编码 /tmp
  • 操作系统层面的 tmpfs:许多 HPC 节点的 /tmp 是 tmpfs(内存盘),容量默认为 RAM 的 50%,当 PT 进程内存压力大时,底层可能发生 swap 行为写入 /tmp

3.4 目录权限或路径不存在

PT 若无法写入指定的 pt_tmp_dir,通常会静默回退到 /tmp,没有任何报错提示。

1
2
3
# 确保目录存在且可写
mkdir -p /tmpdata/pt_scratch/$USER
chmod 700 /tmpdata/pt_scratch/$USER

四、推荐配置方案

4.1 单机多核场景

.synopsys_pt.setup(放置于项目目录或 $HOME)中:

1
2
3
4
5
# 临时文件重定向
set_app_var pt_tmp_dir "/tmpdata/pt_scratch/[exec id -un]"

# 多核工作目录(若使用 multicore)
set_app_var multi_core_working_directory "/tmpdata/pt_mc/[exec id -un]"

在 LSF 提交脚本中同步设置 Shell 层面的 TMPDIR

1
2
3
4
5
6
7
#BSUB -J pt_run
#BSUB -n 8

export TMPDIR=/tmpdata/pt_scratch/$USER
mkdir -p $TMPDIR

pt_shell -f run.tcl

4.2 DMSA 分布式多场景

1
2
3
4
5
# master run.tcl
set_app_var multi_scenario_working_directory "/nfs_shared/pt_dmsa/$env(USER)"

# 各 slave 的 .synopsys_pt.setup(放在 $HOME 或项目共享 HOME_PT_SETUP 路径)
set_app_var pt_tmp_dir "/tmpdata/pt_scratch/$env(USER)/[exec hostname]"

LSF 提交脚本同步设置:

1
2
3
4
5
6
7
#BSUB -J pt_dmsa
#BSUB -n 1  # master
export TMPDIR=/tmpdata/pt_scratch/$USER
mkdir -p $TMPDIR

# 确保 HOME 中的 .synopsys_pt.setup 可被 slave host 读取
pt_shell -f dmsa_run.tcl

4.3 节点级批量初始化(系统管理员)

若无法修改用户脚本,系统管理员可在节点的 compute 节点部署 prologue 脚本(LSF PRE_EXEC):

1
2
3
4
#!/bin/bash
# /etc/lsf/prologue.sh
mkdir -p /tmpdata/pt_scratch/$LSB_JOBUSER
chown $LSB_JOBUSER /tmpdata/pt_scratch/$LSB_JOBUSER

并通过 module 文件为用户自动设置:

1
2
# module file for primetime
setenv TMPDIR /tmpdata/pt_scratch/$env(USER)

五、诊断方法

当不确定 PT 实际在哪里写临时文件时,可以使用如下方法排查:

1
2
3
4
5
6
7
8
9
10
11
# 方法1:实时监控 /tmp 中 PT 进程写入的文件(按 PID 过滤)
PID=$(pgrep -f pt_shell | head -1)
lsof -p $PID | grep /tmp

# 方法2:strace 追踪文件创建(适合开发环境,不建议生产环境)
strace -f -e trace=openat,creat -o /tmp/pt_strace.log pt_shell -f run.tcl 2>&1 &

# 方法3:在 PT 内部检查变量值
# 在 pt_shell 交互模式中:
printvar pt_tmp_dir
printvar multi_core_working_directory

六、变量速查表

变量 类型 默认值 是否传播到 Slave 作用范围
pt_tmp_dir PT app_var /tmp ❌ 需手动配置到每个 Slave 的 .synopsys_pt.setup high capacity 模式下寄生参数临时文件
multi_core_working_directory PT app_var PT 启动时的工作目录 ❌ 需配置为所有节点可访问的共享路径 多核分析 Worker 工作目录
multi_scenario_working_directory PT app_var PT 启动时的工作目录 ❌ 需配置为所有节点可访问的共享路径 DMSA 全场景共享工作目录
TMPDIR Shell 环境变量 /tmp 取决于 LSF/SGE 的 -env 配置 底层 C 库及第三方库临时文件

七、总结

PT 计算节点 /tmp 被撑满的核心原因在于:

  1. pt_tmp_dir 是 PT app_var,不是 Shell 环境变量,无法通过 export/setenv 生效,必须用 set_app_var 写入 PT 启动时读取的 .synopsys_pt.setup
  2. Slave 进程独立启动,不继承 Master 的 app_var 设置,每个 Slave 都需要自己的完整配置。
  3. 临时文件有多个来源,仅设置 pt_tmp_dir 无法覆盖底层库的行为,需同时设置 Shell 层的 TMPDIR
  4. 目标路径需提前创建且用户具备写权限,否则 PT 静默回退到 /tmp

推荐的完整方案是:在项目共享目录的 .synopsys_pt.setup 中配置所有 Tcl 路径变量,同时在 LSF/SGE 提交脚本中 export TMPDIR 并提前 mkdir -p,从两个维度同时覆盖临时文件的写入路径。