跳转至

SOP — Lmod family 作用域修正(Cadence 与 Calibre 环境共存)

变更日期:2026-09-27 | 状态:实施完成并验证通过 变更对象:slurm_ins 部署工程(模块生成器 + 站点配置) 交付目录:slurm_ins/module_family_scope_20260927/

1. 背景

为什么要做。 IC617 安装工程做幂等复跑验收时,在 module 环境层发现一处设计偏差:

  • 三家 EDA 工具的 site 家族入口(Core/cadence.lua、Core/siemens.lua、Core/synopsys.lua)都声明了 family("eda_suite")。Lmod 的 family 是互斥标签:同一时刻同标签只能有一个 active,加载第二个会把第一个置为 Inactive 并撤销其环境变量。实测加载 siemens 后,virtuoso/IC06.17.700 变为 Inactive、CDS_LIC_FILE 被清空。
  • 而真正的工具模块(cadence/virtuoso/*.lua、siemens/calibre/*.lua)没有任何 family 声明,生成器 render_tool_module() 也没有输出该行的逻辑。

结果保护落在了错误的位置:跨厂商被强制互斥(而 EDA 流程恰恰需要混用),同厂商多版本反而毫无约束。

触发条件:待办的「Calibre ↔ Virtuoso 集成」要求同一 shell 会话内两家环境同时可见,当前设计下无法准备。

2. 目标

  1. 跨厂商可共存:同一 shell 内 module load cadence 与 module load siemens 同时 active,CDS_LIC_FILE 与 MGLS_LICENSE_FILE 并存
  2. 同工具多版本互斥的机制就位:生成器支持工具级 family_tag,供后续把 IC617 纳入配置时复用同一标签
  3. 不回归:Cadence 三工具版本与 license 实时 checkout 不受影响
  4. 幂等:连续执行两次,第二次零变更、全跳过

3. 前置条件

项 要求 本次实测
SSH 操作机 → 集群节点 root 免密 通(.16/.17/.18/.19/.20/.28)
共享盘 宿主导出 /data/nfs/modulefiles,节点挂载至 /opt/modulefiles .16 侧 findmnt 显示 192.168.31.249:/data/nfs/modulefiles rw
作业 无在跑作业;本次只改共享盘普通文件,不重启服务 通过
Lmod 节点已装 Lmod 8.7.65 已装
备份 改动前已完成备份(见第 7 章) 完成

4. 影响范围

  • 主机:部署器管辖 .16/.17/.18/.19/.20/.28;实际写入发生在内容生成节点 .16(写 NFS 共享盘),其余节点经共享挂载一并生效
  • 波及:lsf-work-01/02/03(.25/.26/.27)虽不在部署器节点清单内,但挂载同一份 /opt/modulefiles,改动同样生效
  • 文件:6 个 modulefile(见步骤 6)
  • 无需停服:modulefile 是共享盘上的普通文件,不影响运行中作业;本次 slurm.conf 与 TaskProlog 未变更(幂等比对判定为一致)

5. 分步操作

实现体:slurm_ins/module_env_assets.py、module_env_deployer.py、config/slurm_deploy.yaml 下列代码块为与实现体等价的操作序列,供复核与手工复现;幂等与错误处理由实现体保证。

步骤 1:备份(高危动作的前置)

改的是六台共用的共享盘与部署工程源码,先整体留底。备份落在交付目录 backup/ 下(结构见第 7 章)。

TS=$(date +%Y%m%d-%H%M%S); DEST=<交付目录>
mkdir -p "$DEST/backup/slurm_ins/config" "$DEST/backup/modulefiles"
cp -a <工程>/config/slurm_deploy.yaml "$DEST/backup/slurm_ins/config/slurm_deploy.yaml.bak.$TS"
cp -a <工程>/module_env_assets.py     "$DEST/backup/slurm_ins/module_env_assets.py.bak.$TS"
cp -a <工程>/module_env_deployer.py   "$DEST/backup/slurm_ins/module_env_deployer.py.bak.$TS"
cp -a /data/nfs/modulefiles/.         "$DEST/backup/modulefiles/"

预期:backup/ 下 3 个源码备份 + 13 个 modulefile(保持原树结构)。 失败判断:共享盘不可读 → 先确认 .16 的 /opt/modulefiles 挂载,再重试。

步骤 2:生成器支持工具级 family

在 render_tool_module() 的目录守卫之后、prepend_path 之前插入(不配置则不生成该行,对既有 modulefile 向后兼容):

        # 工具级 family:让同一工具的不同版本互斥(如 virtuoso/IC617 与 IC25.10)。
        # 不配置则不生成该行,对既有 modulefile 向后兼容。跨厂商共存与否则由
        # 家族入口的 family_tag 决定——两处标签取值不同即不互斥。
        tool_tag = str(tool.get("family_tag", "")).strip()
        if tool_tag:
            lines.append(f'family("{tool_tag}")   -- 同工具多版本互斥')
            lines.append("")

坑:该行必须放在目录守卫之后——守卫用 LmodError 在工具未就位时中止加载,family 声明排在其后语义才正确(工具根本不存在就不该参与互斥判定)。

grep -n "tool_tag" <工程>/module_env_assets.py     # 预期 4 处命中

步骤 3:配置设 family_tag

config/slurm_deploy.yaml 的 module_env.families[],家族级取不同值(解除跨厂商互斥),同工具各版本取同一值(实现版本互斥):

    - name: "cadence"
      family_tag: "cadence"              # 与 siemens/synopsys 不同族 → 可同时加载
      tools:
        - name: "virtuoso"
          version: "IC25.10.000"
          family_tag: "cadence_virtuoso" # 后续纳入 IC617 时沿用此标签即实现版本互斥
    - name: "synopsys"
      family_tag: "synopsys"
      tools: [...]
    - name: "siemens"
      family_tag: "siemens"
      tools: [...]
grep -n "family_tag" <工程>/config/slurm_deploy.yaml   # 预期 7 处(pdk 原有 1 + 新增 6)

步骤 4:新增配置项校验

按"新增配置项必须同时写样例、加校验、被实现体引用",在 module_env_deployer.py 增加标签字符合法性校验(字母数字与下划线/连字符,不含点与空格):

FAMILY_TAG_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_\-]*$")

并在 validate_config() 的家族循环内,对家族级与工具级 family_tag 各加一处判定。校验不通过时按 家族名/标签 定位输出。

步骤 5:干跑复核(零改动)

<工程>/.venv/bin/python main.py --config config/slurm_deploy.yaml --module-env --dry-run

预期:待执行变更 8(6 个 modulefile + backup 记录)、幂等跳过 26、退出码 0;/etc/lmod/lmod_config.lua、/etc/profile.d/zzz_site_lmod.sh、/etc/slurm/task_prolog_lmod.sh 三项均显示「内容一致 → 跳过」。 失败判断:出现 BLOCK 级预检查项或待变更集合超出上述 6 个文件 → 停止,先核对配置与共享盘状态。

步骤 6:正式执行

<工程>/.venv/bin/python main.py --config config/slurm_deploy.yaml --module-env

预期:待执行变更 7、幂等跳过 26、退出码 0;写入集中在校验节点 .16 的 /opt/modulefiles,逐文件 chmod 644。

实际写入的 6 个文件与内容变化:

文件 变化
Core/cadence.lua family("eda_suite") → family("cadence")
Core/siemens.lua family("eda_suite") → family("siemens")
Core/synopsys.lua family("eda_suite") → family("synopsys")
cadence/virtuoso/IC25.10.000.lua 新增 family("cadence_virtuoso")
synopsys/vcs/2023.12.lua 新增 family("synopsys_vcs")
siemens/calibre/2026.1.lua 新增 family("siemens_calibre")

未受影响(不在生成器管辖,本次未被触碰):cadence/virtuoso/IC06.17.700.lua、siemens/calibre/2015.2_36.27.lua、Core/site.lua、Core/pdk.lua、Core/slurm/26.05.2.lua、pdk/sky130/1.0.lua。

6. 验证

验证项 命令 判据 实测
跨厂商共存 节点上 bash -lc 'module load cadence; module load virtuoso/IC06.17.700; module load siemens; module load calibre/2015.2_36.27; module list' 四个模块同屏 active,无 Inactive 通过(六台一致)
环境变量并存 同上后 echo $CDS_LIC_FILE $MGLS_LICENSE_FILE 5280@192.168.31.29 与 /tools/mentor/calibre/license.dat 同时存在 通过
命令可达 同上后 command -v virtuoso calibre 两者均返回真实路径 通过
license 无回归 `bash -lc 'module load cadence; module load virtuoso/IC06.17.700; cd /tmp; timeout 120 virtuoso -nograph