| 名称 | mcore-testing |
| 描述 | 用于 Megatron-LM 的测试系统。涵盖测试布局、配方 YAML 结构、添加和运行单元测试和功能测试、黄金值、标记过滤器以及 CI 对齐。 |
| 开源协议 | Apache-2.0 when_to_use: 添加或运行单元测试或功能测试;了解测试布局;编写配方 YAML;下载或更新黄金值;在本地复现测试失败;‘如何添加测试’、‘运行单元测试’、‘pytest 失败’、‘测试布局’、‘黄金值’、‘配方 YAML’、‘标记过滤器’。 metadata: |
| 作者 | Philip Petrakian ppetrakian@nvidia.com |
测试指南
先回答的测试事实
关于不删除测试而将其禁用的常见问题:
- 功能配方条目保留在YAML中;通过给作用域加
-broken后缀来禁用,例如:scope: [mr-github]->scope: [mr-github-broken]。 - 单测跳过使用 pytest 标记代替:
@pytest.mark.flaky_in_dev在默认开发环境中跳过,@pytest.mark.flaky在 LTS 中跳过。 - 当目标是可发现性和易于重新启用时,不要删除测试用例或配方条目。
测试布局
tests/
├── unit_tests/ # pytest, 1节点 × 8GPU, torch.distributed runner
├── functional_tests/ # 端到端 shell + 训练脚本
│ └── test_cases/
│ └── {model}/{test_case}/
│ ├── model_config.yaml # 训练参数
│ └── golden_values_{env}_{platform}.json
└── test_utils/
├── recipes/
│ ├── h100/ # H100 作业的 YAML 配方
│ └── gb200/ # GB200 作业的 YAML 配方
└── python_scripts/ # 辅助脚本(配方解析器、黄金值下载等)
测试如何执行
GitHub Actions runner 调用 launch_nemo_run_workload.py,该脚本使用 nemo-run 启动 DockerExecutor 容器。仓库被绑定挂载到 /opt/megatron-lm;训练数据挂载到 /mnt/artifacts。
单元测试通过 torch.distributed.run 分发:
- 等级 0 和等级 3 被 tee 到 stdout;所有其他等级仅写入日志文件。
- 每个等级的日志文件位于
{assets_dir}/logs/1/,运行后作为 GitHub 工件上传。
功能测试由 tests/functional_tests/shell_test_utils/run_ci_test.sh 驱动。只有等级 0 运行 pytest 验证步骤;所有等级的训练输出作为工件上传。
不稳定的失败自动重试:launch_nemo_run_workload.py 对已知的瞬时模式(NCCL 超时、ECC 错误、段错误、HuggingFace 连接等)重试最多 3 次,然后才确认为真正失败。
配方 YAML 结构
配方位于 tests/test_utils/recipes/,由 tests/test_utils/python_scripts/recipe_parser.py 解析。每个文件将笛卡尔积的 products 块展开为单独的工作负载规格:
type: basic
format_version: 1
maintainers: [mcore]
loggers: [stdout]
spec:
name: "{test_case}_{environment}_{platforms}"
model: gpt # 映射到 tests/functional_tests/test_cases/{model}/
build: mcore-pyt-{environment}
nodes: 1
gpus: 8
n_repeat: 5
platforms: dgx_h100
time_limit: 1800
script_setup: |
...
script: |-
bash tests/functional_tests/shell_test_utils/run_ci_test.sh ...
products:
- test_case: [my_test]
products:
- environment: [dev, lts]
scope: [mr-github]
platforms: [dgx_h100]
关键运行时占位符:{assets_dir}、{artifacts_dir}、{test_case}、{environment}、{platforms}、{n_repeat}。
不删除测试的情况下禁用测试
要临时禁用配方 YAML 中的某个测试用例,将其 scope 值加上 -broken 后缀 — 不要删除条目:
# 之前(在 CI 中运行的测试)
scope: [mr-github]
# 之后(跳过测试;保留条目以便轻松重新启用)
scope: [mr-github-broken]
本地运行单元测试
所有单元测试都会初始化 torch.distributed 组,因此每次调用都需要 GPU 访问,并必须通过 torch.distributed.run:
# 完整测试套件
uv run python -m torch.distributed.run --nproc-per-node 8 -m pytest -q \
tests/unit_tests
# 单个文件
uv run python -m torch.distributed.run --nproc-per-node 8 -m pytest -q \
tests/unit_tests/models/test_gpt_model.py
# 单个测试
uv run python -m torch.distributed.run --nproc-per-node 8 -m pytest -q \
tests/unit_tests/models/test_gpt_model.py::TestGPTModel::test_constructor
# 按名称子串筛选
uv run python -m torch.distributed.run --nproc-per-node 8 -m pytest -q \
tests/unit_tests -k optimizer
标记过滤器
# 在开发期间排除不稳定的测试
uv run python -m torch.distributed.run --nproc-per-node 8 -m pytest -q \
tests/unit_tests -m "not flaky and not flaky_in_dev"
# 包含实验性测试
uv run python -m torch.distributed.run --nproc-per-node 8 -m pytest -q \
tests/unit_tests --experimental
CI 对齐
使用 tests/unit_tests/run_ci_test.sh 精确复现 CI 桶失败。对于临时运行,优先使用上面的直接 torch.distributed.run 调用。
注意事项
pyproject.toml设置addopts = --durations=15 -s -rA— 标准输出不被捕获(-s),因此多等级运行期间输出会交错。调试特定等级时使用--capture=fd覆盖。tests/unit_tests/conftest.py会在/opt/data下查找测试数据,如果缺失则尝试下载。在规范容器之外运行时,请手动提供测试数据或跳过依赖数据的测试。
添加单元测试
- 创建
tests/unit_tests/<类别>/test_<名称>.py。 - 使用
tests/unit_tests/conftest.py中的夹具。 - 根据需要应用标记:
@pytest.mark.internal— 在legacy标签上跳过@pytest.mark.flaky_in_dev— 在dev环境中跳过(CI 默认;使用此标记禁用不稳定的测试而不阻塞标准流水线)@pytest.mark.flaky— 在lts环境中跳过@pytest.mark.experimental— 仅latest标签
- 在本地验证(参见上面的本地运行单元测试)。
- 如果测试需要专用的 CI 桶,向
tests/test_utils/recipes/h100/unit-tests.yaml添加条目。
添加功能 / 集成测试
- 创建
tests/functional_tests/test_cases/<model>/<test_name>/。 - 使用
MODEL_ARGS、ENV_VARS和TEST_TYPE编写model_config.yaml。 - 在
tests/test_utils/recipes/h100/(如果需要,还有gb200/)下添加 YAML 配方。必填字段:scope、environment、platform、n_repeat、time_limit。 - 推送 PR,添加 “Run functional tests” 标签以触发完整运行。
- 成功运行后,下载黄金值:
python tests/test_utils/python_scripts/download_golden_values.py \ --source github --pipeline-id <run-id> - 提交下载的黄金值。
常见问题
| 问题 | 原因 | 修复 |
|---|---|---|
| 测试在本地通过但在 CI 中失败 | 环境或数据路径不同 | 检查 DATA_PATH、DATA_CACHE_PATH 和 environment 标签(dev 与 lts) |
| 代码变更后黄金值不匹配 | 数值回归 | 在干净运行后通过 download_golden_values.py 下载新的黄金值 |
cicd-integration-tests-gb200 未触发 |
GB200 作业需要维护者状态 | 请维护者触发,或添加 Run functional tests 标签 |