Skip to content

Commit c0c75d1

Browse files
author
zhoujiamei
committed
add L0 unit test
1 parent c88f447 commit c0c75d1

1 file changed

Lines changed: 86 additions & 189 deletions

File tree

.github/workflows/unit_tests_common.yml

Lines changed: 86 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -27,99 +27,37 @@ on:
2727
required: false
2828
type: string
2929
default: ''
30-
description: JSON array of test files to ignore (e.g., '["tests/unit_tests/test_a.py", "tests/unit_tests/test_b.py"]')
30+
description: JSON array of test files to ignore
3131

3232
jobs:
33-
# Detect which test groups need to run based on changed files
33+
# 1. Change Detection: Monitors both new unit tests and legacy QA paths
3434
detect_changes:
3535
runs-on: ubuntu-latest
3636
outputs:
3737
core: ${{ steps.filter.outputs.core }}
38-
transformer: ${{ steps.filter.outputs.transformer }}
39-
models: ${{ steps.filter.outputs.models }}
40-
distributed: ${{ steps.filter.outputs.distributed }}
41-
dist_checkpointing: ${{ steps.filter.outputs.dist_checkpointing }}
42-
tensor_parallel: ${{ steps.filter.outputs.tensor_parallel }}
43-
pipeline_parallel: ${{ steps.filter.outputs.pipeline_parallel }}
44-
data: ${{ steps.filter.outputs.data }}
45-
fusions: ${{ steps.filter.outputs.fusions }}
46-
others: ${{ steps.filter.outputs.others }}
38+
qa_l0: ${{ steps.filter.outputs.qa_l0 }}
4739
steps:
4840
- name: Checkout source code
49-
uses: actions/checkout@v6
41+
uses: actions/checkout@v4
5042
with:
5143
fetch-depth: 0
5244

5345
- name: Detect changed paths
5446
id: filter
5547
run: |
5648
set -euo pipefail
57-
58-
# Get the base ref for comparison
59-
if [ "${{ github.event_name }}" == "pull_request" ]; then
60-
BASE_REF="origin/${{ github.base_ref }}"
61-
git fetch origin ${{ github.base_ref }} --depth=1
62-
else
63-
# For push events, compare with the previous commit
64-
BASE_REF="HEAD~1"
65-
fi
66-
# Get list of changed files
49+
# Identify base reference for diff
50+
BASE_REF="${{ github.event_name == 'pull_request' && format('origin/{0}', github.base_ref) || 'HEAD~1' }}"
51+
[ "${{ github.event_name }}" == "pull_request" ] && git fetch origin ${{ github.base_ref }} --depth=1
52+
6753
CHANGED_FILES=$(git diff --name-only $BASE_REF...HEAD 2>/dev/null || git diff --name-only $BASE_REF HEAD)
6854
69-
# Function to check if any pattern matches
70-
check_patterns() {
71-
local patterns="$1"
72-
for pattern in $patterns; do
73-
if echo "$CHANGED_FILES" | grep -qE "$pattern"; then
74-
echo "true"
75-
return
76-
fi
77-
done
78-
echo "false"
79-
}
80-
81-
# Core tests: root-level test files and core megatron files
82-
CORE_PATTERNS="^tests/unit_tests/test_.*\.py$ ^megatron/core/[^/]*\.py$ ^megatron/core/__init__\.py$"
83-
echo "core=$(check_patterns "$CORE_PATTERNS")" >> $GITHUB_OUTPUT
84-
85-
# Transformer tests
86-
TRANSFORMER_PATTERNS="^tests/unit_tests/transformer/ ^megatron/core/transformer/"
87-
echo "transformer=$(check_patterns "$TRANSFORMER_PATTERNS")" >> $GITHUB_OUTPUT
88-
89-
# Models tests
90-
MODELS_PATTERNS="^tests/unit_tests/models/ ^megatron/core/models/"
91-
echo "models=$(check_patterns "$MODELS_PATTERNS")" >> $GITHUB_OUTPUT
92-
93-
# Distributed tests
94-
DISTRIBUTED_PATTERNS="^tests/unit_tests/distributed/ ^megatron/core/distributed/"
95-
echo "distributed=$(check_patterns "$DISTRIBUTED_PATTERNS")" >> $GITHUB_OUTPUT
96-
97-
# Dist checkpointing tests
98-
DIST_CKPT_PATTERNS="^tests/unit_tests/dist_checkpointing/ ^megatron/core/dist_checkpointing/"
99-
echo "dist_checkpointing=$(check_patterns "$DIST_CKPT_PATTERNS")" >> $GITHUB_OUTPUT
100-
101-
# Tensor parallel tests
102-
TP_PATTERNS="^tests/unit_tests/tensor_parallel/ ^megatron/core/tensor_parallel/"
103-
echo "tensor_parallel=$(check_patterns "$TP_PATTERNS")" >> $GITHUB_OUTPUT
104-
105-
# Pipeline parallel tests
106-
PP_PATTERNS="^tests/unit_tests/pipeline_parallel/ ^megatron/core/pipeline_parallel/"
107-
echo "pipeline_parallel=$(check_patterns "$PP_PATTERNS")" >> $GITHUB_OUTPUT
108-
109-
# Data tests
110-
DATA_PATTERNS="^tests/unit_tests/data/ ^megatron/core/datasets/"
111-
echo "data=$(check_patterns "$DATA_PATTERNS")" >> $GITHUB_OUTPUT
112-
113-
# Fusions tests
114-
FUSIONS_PATTERNS="^tests/unit_tests/fusions/ ^megatron/core/fusions/"
115-
echo "fusions=$(check_patterns "$FUSIONS_PATTERNS")" >> $GITHUB_OUTPUT
116-
117-
# Others tests (export, post_training, tokenizers, utils)
118-
OTHERS_PATTERNS="^tests/unit_tests/export/ ^tests/unit_tests/post_training/ ^tests/unit_tests/tokenizers/ ^tests/unit_tests/utils/ ^megatron/core/export/ ^megatron/post_training/ ^megatron/tokenizer/ ^megatron/core/utils/"
119-
echo "others=$(check_patterns "$OTHERS_PATTERNS")" >> $GITHUB_OUTPUT
120-
121-
echo "=== Change detection complete ==="
55+
# Logic for core framework and new pytest suite
56+
echo "core=$(echo "$CHANGED_FILES" | grep -qE "^tests/unit_tests/|^megatron/core/" && echo "true" || echo "false")" >> $GITHUB_OUTPUT
57+
# Logic for legacy QA L0 scripts and PyTorch specific paths
58+
echo "qa_l0=$(echo "$CHANGED_FILES" | grep -qE "^qa/L0_|^transformer_engine/|^tests/pytorch/" && echo "true" || echo "false")" >> $GITHUB_OUTPUT
12259
60+
# 2. Unified Test Execution: Supports both pytest and legacy shell scripts
12361
unit_test:
12462
needs: detect_changes
12563
defaults:
@@ -130,153 +68,112 @@ jobs:
13068
fail-fast: false
13169
matrix:
13270
test_group:
71+
# Modern Pytest architecture
13372
- name: core
13473
path: "tests/unit_tests/test_*.py"
135-
description: "Core unit tests"
136-
- name: transformer
137-
path: "tests/unit_tests/transformer/"
138-
description: "Transformer tests"
139-
- name: models
140-
path: "tests/unit_tests/models/"
141-
description: "Model tests"
74+
test_type: "pytest"
14275
- name: distributed
14376
path: "tests/unit_tests/distributed/"
144-
description: "Distributed tests"
145-
- name: dist_checkpointing
146-
path: "tests/unit_tests/dist_checkpointing/"
147-
description: "Distributed checkpointing tests"
148-
- name: tensor_parallel
149-
path: "tests/unit_tests/tensor_parallel/"
150-
description: "Tensor parallel tests"
151-
- name: pipeline_parallel
152-
path: "tests/unit_tests/pipeline_parallel/"
153-
description: "Pipeline parallel tests"
154-
- name: data
155-
path: "tests/unit_tests/data/"
156-
description: "Data tests"
157-
- name: fusions
158-
path: "tests/unit_tests/fusions/"
159-
description: "Fusion tests"
160-
- name: others
161-
path: "tests/unit_tests/export/ tests/unit_tests/post_training/ tests/unit_tests/tokenizers/ tests/unit_tests/utils/"
162-
description: "Other tests (a2a_overlap, export, post_training, tokenizers, utils)"
77+
test_type: "pytest"
78+
79+
# Integrated legacy QA L0 groups
80+
- name: pytorch_unittest
81+
path: "qa/L0_pytorch_unittest/test.sh"
82+
test_type: "sh"
83+
- name: pytorch_debug
84+
path: "qa/L0_pytorch_debug_unittest/test.sh"
85+
test_type: "sh"
86+
- name: pytorch_lint
87+
path: "qa/L0_pytorch_lint/test.sh"
88+
test_type: "sh"
89+
- name: pytorch_wheel
90+
path: "qa/L0_pytorch_wheel/test.sh"
91+
test_type: "sh"
92+
16393
name: unit-${{ inputs.device }}-${{ matrix.test_group.name }}
16494
container:
16595
image: ${{ inputs.image }}
166-
16796
ports:
16897
- 80
16998
volumes: ${{ fromJson(inputs.container_volumes) }}
170-
# options: ${{ inputs.container_options }}
99+
# Crucial: --pull never prevents internet access; container_options should include --privileged
171100
options: --pull never ${{ inputs.container_options }}
101+
172102
steps:
173-
# Check if this test group should run based on changed files or "full ci" label
174103
- name: Check if tests should run
175104
id: should_run
176105
run: |
177-
TEST_GROUP='${{ matrix.test_group.name }}'
106+
GROUP='${{ matrix.test_group.name }}'
178107
FULL_CI='${{ contains(github.event.pull_request.labels.*.name, 'full ci') }}'
179-
180-
# If "full ci" label is present, run all tests
181-
if [ "$FULL_CI" == "true" ]; then
182-
echo "should_run=true" >> $GITHUB_OUTPUT
183-
exit 0
108+
109+
if [ "$FULL_CI" == "true" ]; then
110+
echo "should_run=true" >> $GITHUB_OUTPUT; exit 0
184111
fi
185112
186-
# Check change detection output for this test group
187-
case "$TEST_GROUP" in
188-
core) CHANGED='${{ needs.detect_changes.outputs.core }}' ;;
189-
transformer) CHANGED='${{ needs.detect_changes.outputs.transformer }}' ;;
190-
models) CHANGED='${{ needs.detect_changes.outputs.models }}' ;;
191-
distributed) CHANGED='${{ needs.detect_changes.outputs.distributed }}' ;;
192-
dist_checkpointing) CHANGED='${{ needs.detect_changes.outputs.dist_checkpointing }}' ;;
193-
tensor_parallel) CHANGED='${{ needs.detect_changes.outputs.tensor_parallel }}' ;;
194-
pipeline_parallel) CHANGED='${{ needs.detect_changes.outputs.pipeline_parallel }}' ;;
195-
data) CHANGED='${{ needs.detect_changes.outputs.data }}' ;;
196-
fusions) CHANGED='${{ needs.detect_changes.outputs.fusions }}' ;;
197-
others) CHANGED='${{ needs.detect_changes.outputs.others }}' ;;
198-
*) CHANGED="true" ;;
199-
esac
200-
113+
if [[ "$GROUP" == "pytorch_"* ]]; then
114+
CHANGED='${{ needs.detect_changes.outputs.qa_l0 }}'
115+
else
116+
CHANGED='${{ needs.detect_changes.outputs.core }}'
117+
fi
201118
echo "should_run=$CHANGED" >> $GITHUB_OUTPUT
202-
203119
204120
- name: Checkout source code
205121
if: steps.should_run.outputs.should_run == 'true'
206-
uses: actions/checkout@v6
122+
uses: actions/checkout@v4
207123
with:
208-
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
209-
ref: ${{ github.event.pull_request.head.ref || github.ref }}
210-
ssh-strict: true
211-
ssh-user: git
212-
ssh-key: ${{ secrets.RUNNER_SSH_KEY }}
213-
persist-credentials: false
214-
clean: true
215-
sparse-checkout-cone-mode: true
216-
fetch-tags: false
217-
show-progress: true
218-
lfs: false
219-
220-
- name: Set safe directory
221-
if: steps.should_run.outputs.should_run == 'true'
222-
run: |
223-
git config --global --add safe.directory $GITHUB_WORKSPACE
124+
set-safe-directory: true
224125

225-
- name: Setup Python environment
126+
- name: Metax Environment Setup
226127
if: steps.should_run.outputs.should_run == 'true'
227-
working-directory: ${{ github.workspace }}
228128
run: |
229129
set -euo pipefail
230-
echo "Python location: $(which python)"
231-
echo "Python version: $(python --version)"
232-
# Install package in development mode
233-
pip install boto3==1.42.1
130+
# Dynamically set MACA library path if drivers are mounted
131+
if [ -d "/usr/local/maca/lib" ]; then
132+
echo "Setting MACA library path..."
133+
echo "LD_LIBRARY_PATH=/usr/local/maca/lib:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV
134+
fi
135+
136+
# Install dependencies required by legacy QA scripts
137+
pip install --no-cache-dir transformers expecttest boto3==1.42.1
138+
# Install current repo in editable mode without re-building
234139
pip install -e . --no-deps
235-
timeout-minutes: 30
140+
timeout-minutes: 20
236141

237-
- name: Run unit tests - ${{ matrix.test_group.name }}
142+
- name: Execute Tests
238143
if: steps.should_run.outputs.should_run == 'true'
239-
id: unit_test
240144
working-directory: ${{ github.workspace }}
241145
run: |
242146
set -euo pipefail
243-
244-
PLATFORM='${{ inputs.platform }}'
245-
DEVICE='${{ inputs.device }}'
246-
TEST_GROUP='${{ matrix.test_group.name }}'
247-
TEST_PATH='${{ matrix.test_group.path }}'
248-
249-
echo "Running unit tests: $TEST_GROUP"
250-
echo "Test path: $TEST_PATH"
251-
echo "Platform: $PLATFORM"
252-
echo "Device: $DEVICE"
253-
254-
# Set environment variables
147+
148+
# Base environment variables (required for legacy scripts)
149+
export TE_PATH=$GITHUB_WORKSPACE
255150
export PYTHONPATH=$GITHUB_WORKSPACE:${PYTHONPATH:-}
256-
export TORCHINDUCTOR_CACHE_DIR=/tmp/.torch_inductor_cache
257-
mkdir -p $TORCHINDUCTOR_CACHE_DIR
258-
259-
# Build ignore options from ignored_tests input
260-
IGNORED_TESTS='${{ inputs.ignored_tests }}'
261-
IGNORE_OPTS=""
262-
if [ -n "$IGNORED_TESTS" ] && [ "$IGNORED_TESTS" != "[]" ]; then
263-
echo "Parsing ignored tests list..."
264-
# Parse JSON array and build --ignore options
265-
IGNORE_OPTS=$(echo "$IGNORED_TESTS" | python3 -c "import sys, json; tests = json.load(sys.stdin); print(' '.join(['--deselect=' + t for t in tests])) if tests else None")
266-
if [ -n "$IGNORE_OPTS" ]; then
267-
echo "Ignoring tests: $IGNORE_OPTS"
151+
export RUN_LOG=/tmp/te_logs && mkdir -p $RUN_LOG
152+
153+
# Detect local GPU count dynamically (e.g., 2 for C500)
154+
NUM_GPUS=$(python3 -c "import torch; print(torch.cuda.device_count() if torch.cuda.is_available() else 0)")
155+
echo "=== Detected $NUM_GPUS GPUs, starting execution ==="
156+
157+
if [ "${{ matrix.test_group.test_type }}" == "sh" ]; then
158+
echo "::group::Executing Legacy Shell Script"
159+
# Dynamically detect TE installation path to avoid "SO not found" errors
160+
export TE_LIB_PATH=$(python3 -c "import transformer_engine; import os; print(os.path.dirname(transformer_engine.__file__))")
161+
162+
# Special env for Lint group
163+
if [[ "${{ matrix.test_group.name }}" == *"lint"* ]]; then
164+
export CPP_ONLY=0
165+
export PYTHON_ONLY=0
268166
fi
167+
bash ${{ matrix.test_group.path }}
168+
echo "::endgroup::"
169+
else
170+
echo "::group::Executing Modern Pytest"
171+
# Build deselect options from ignored_tests input
172+
IGNORED_TESTS='${{ inputs.ignored_tests }}'
173+
IGNORE_OPTS=$(echo "$IGNORED_TESTS" | python3 -c "import sys, json; t = json.load(sys.stdin); print(' '.join(['--deselect=' + i for i in t])) if t else print('')")
174+
175+
# Run distributed tests with torchrun
176+
torchrun --nproc_per_node=$NUM_GPUS -m pytest -v ${{ matrix.test_group.path }} $IGNORE_OPTS -p no:randomly
177+
echo "::endgroup::"
269178
fi
270-
271-
# Run unit tests with torchrun
272-
# Each test group runs in isolation to avoid state pollution
273-
NUM_GPUS=$(python3 -c "import torch; print(torch.cuda.device_count())")
274-
echo "=== Detected $NUM_GPUS GPUs, starting torchrun ==="
275-
276-
# 使用动态获取的数量启动测试
277-
torchrun --nproc_per_node=$NUM_GPUS -m pytest -v $TEST_PATH $IGNORE_OPTS -p no:randomly
278-
279-
exit_code=$?
280-
echo "exit_code=$exit_code" >> $GITHUB_OUTPUT
281-
exit $exit_code
282-
timeout-minutes: 60
179+
timeout-minutes: 60

0 commit comments

Comments
 (0)