@@ -467,7 +467,7 @@ jobs:
467467 "${RUNNER_ARTIFACT_DIR}/native-sm86-on-sm80.log"
468468
469469 unittest-cuda :
470- name : unittest-cuda
470+ name : unittest-cuda (${{ matrix.shard }})
471471 needs : [changed-files, run-decision]
472472 # This job runs the pybindings device test, so it also has to fire on the
473473 # two pybindings paths the workflow filter lists.
@@ -482,6 +482,13 @@ jobs:
482482 contains(needs.changed-files.outputs.changed-files, 'extension/pybindings') ||
483483 contains(needs.changed-files.outputs.changed-files, 'runtime/__init__.py') ||
484484 needs.run-decision.outputs.is-full-run == 'true'
485+ # kernel: Triton kernels and their autotuning. system: lowering passes, op
486+ # dispatch, export/runtime, and model tests. Together they do not fit the
487+ # timeout.
488+ strategy :
489+ fail-fast : false
490+ matrix :
491+ shard : [kernel, system]
485492 uses : pytorch/test-infra/.github/workflows/linux_job_v3.yml@main
486493 permissions :
487494 id-token : write
@@ -495,6 +502,37 @@ jobs:
495502 ref : ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
496503 script : |
497504 set -eux
505+ SHARD="${{ matrix.shard }}"
506+
507+ # The system shard runs everything under backends/cuda/tests that is not
508+ # listed here, so a new test lands there unless it is added to this list.
509+ KERNEL_TESTS=(
510+ backends/cuda/tests/test_triton_sdpa.py
511+ backends/cuda/tests/test_triton_sdpa_splitk.py
512+ backends/cuda/tests/test_triton_sdpa_nan.py
513+ backends/cuda/tests/test_tq4_sdpa.py
514+ backends/cuda/tests/test_int4_matmul.py
515+ backends/cuda/tests/test_int5_large_quantized_gemm.py
516+ backends/cuda/tests/test_quantized_gemm_family.py
517+ backends/cuda/tests/test_fused_moe.py
518+ backends/cuda/tests/test_fused_deltanet_decode.py
519+ backends/cuda/tests/test_chunk_gated_delta_rule.py
520+ backends/cuda/tests/test_topk.py
521+ backends/cuda/tests/test_autotune_inputs.py
522+ backends/cuda/tests/test_autotune_launch_params.py
523+ backends/cuda/tests/test_triton_mutation_cache.py
524+ )
525+ # These run in unittest-cuda-quantized-gemm.
526+ QUANTIZED_GEMM_TESTS=(
527+ backends/cuda/tests/test_int4_quantized_gemm.py
528+ backends/cuda/tests/test_int4_large_quantized_gemm.py
529+ backends/cuda/tests/test_int5_quantized_gemm.py
530+ backends/cuda/tests/test_int6_quantized_gemm.py
531+ backends/cuda/tests/test_int6_large_quantized_gemm.py
532+ backends/cuda/tests/test_int8_quantized_gemm.py
533+ backends/cuda/tests/test_cuda_graph_timing.py
534+ )
535+
498536 # Install executorch in editable mode so custom op libs land in-tree
499537 bash ./install_executorch.sh
500538
@@ -503,64 +541,67 @@ jobs:
503541 conda install -y -c conda-forge 'libstdcxx-ng>=12'
504542 export LD_LIBRARY_PATH=/opt/conda/lib:$LD_LIBRARY_PATH
505543
506- # The pybindings loader only asks for device memory on a build that has
507- # a device allocator registered, so these tests cannot run in the CPU
508- # jobs. They need the install above and nothing built below, so run them
509- # here and fail before the long builds.
510- #
511- # unittest exits 0 when a test skips, and these tests skip when the CUDA
512- # backend is missing or no GPU is visible. Both are the prerequisites
513- # this job exists to provide, so treat a skip as a failure rather than
514- # let a packaging regression pass silently. `tee` would otherwise hide
515- # the real exit status behind its own, so read it back explicitly.
516- set +e
517- python -m unittest -v \
518- executorch.extension.pybindings.test.test_pybindings.PybindingsTest.test_device_planned_method_allocates_on_the_device \
519- executorch.extension.pybindings.test.test_pybindings.PybindingsTest.test_unplanned_device_output_is_device_memory \
520- 2>&1 | tee /tmp/pybindings_device_test.log
521- pybindings_device_status=${PIPESTATUS[0]}
522- set -e
523- if [ "${pybindings_device_status}" -ne 0 ]; then
524- echo "::error::a pybindings device test failed"
525- exit "${pybindings_device_status}"
526- fi
527- if grep -qE "^OK \(skipped=|skipped=[1-9]" /tmp/pybindings_device_test.log; then
528- echo "::error::a pybindings device test skipped in the CUDA job, which means the CUDA backend or a visible GPU is missing"
529- exit 1
544+ if [ "${SHARD}" = "system" ]; then
545+ # The pybindings loader only asks for device memory on a build that has
546+ # a device allocator registered, so these tests cannot run in the CPU
547+ # jobs. They need the install above and nothing built below, so run them
548+ # here and fail before the long builds.
549+ #
550+ # unittest exits 0 when a test skips, and these tests skip when the CUDA
551+ # backend is missing or no GPU is visible. Both are the prerequisites
552+ # this job exists to provide, so treat a skip as a failure rather than
553+ # let a packaging regression pass silently. `tee` would otherwise hide
554+ # the real exit status behind its own, so read it back explicitly.
555+ set +e
556+ python -m unittest -v \
557+ executorch.extension.pybindings.test.test_pybindings.PybindingsTest.test_device_planned_method_allocates_on_the_device \
558+ executorch.extension.pybindings.test.test_pybindings.PybindingsTest.test_unplanned_device_output_is_device_memory \
559+ 2>&1 | tee /tmp/pybindings_device_test.log
560+ pybindings_device_status=${PIPESTATUS[0]}
561+ set -e
562+ if [ "${pybindings_device_status}" -ne 0 ]; then
563+ echo "::error::a pybindings device test failed"
564+ exit "${pybindings_device_status}"
565+ fi
566+ if grep -qE "^OK \(skipped=|skipped=[1-9]" /tmp/pybindings_device_test.log; then
567+ echo "::error::a pybindings device test skipped in the CUDA job, which means the CUDA backend or a visible GPU is missing"
568+ exit 1
569+ fi
530570 fi
531571
532572 # Build ExecuTorch with CUDA support
533573 cmake --workflow --preset llm-release-cuda
534574
535- # Build and run CUDA shim tests (C++)
536- pushd backends/cuda/runtime/shims/tests
537- cmake --workflow --preset default
538- popd
575+ if [ "${SHARD}" = "system" ]; then
576+ # Build and run CUDA shim tests (C++)
577+ pushd backends/cuda/runtime/shims/tests
578+ cmake --workflow --preset default
579+ popd
580+ fi
539581
540582 # Install flash-linear-attention for chunk_gated_delta_rule triton kernel tests
541583 pip install "flash-linear-attention==0.4.2"
542584
543- # Build executor_runner (needed by CUDA backend e2e tests)
585+ # Build executor_runner (needed by CUDA backend e2e tests in both shards )
544586 cmake --build cmake-out --target executor_runner
545587
546- # Run CUDA backend Python tests. The quantized GEMM kernel suites run
547- # in unittest-cuda-quantized-gemm; together they do not fit this
548- # job's timeout.
549- python -m pytest backends/cuda/tests backends/cuda/passes/tests -v -o "addopts=" \
550- --ignore=backends/cuda/tests/test_int4_quantized_gemm.py \
551- --ignore=backends/cuda/tests/test_int4_large_quantized_gemm.py \
552- --ignore=backends/cuda/tests/test_int5_quantized_gemm.py \
553- --ignore=backends/cuda/tests/test_int6_quantized_gemm.py \
554- --ignore=backends/cuda/tests/test_int6_large_quantized_gemm.py \
555- --ignore=backends/cuda/tests/test_int8_quantized_gemm.py \
556- --ignore=backends/cuda/tests/test_cuda_graph_timing.py
557-
558- # Run Qwen 3.5 MoE tests (quantize roundtrip + TurboQuant KV cache + sampler)
559- python -m pytest examples/models/qwen3_5_moe/test_quantize_roundtrip.py examples/models/qwen3_5_moe/test_turboquant.py examples/models/qwen3_5_moe/test_sampler.py -v -o "addopts="
560-
561- # Run Gemma 4 31B tests (quant unit tests + pipeline integration tests)
562- pip install gguf
563- python -m pytest examples/models/gemma4_31b/tests/ --ignore=examples/models/gemma4_31b/tests/test_mlx_pipeline.py -v -o "addopts="
588+ if [ "${SHARD}" = "kernel" ]; then
589+ python -m pytest "${KERNEL_TESTS[@]}" -v -o "addopts=" --durations=20
590+ else
591+ IGNORES=()
592+ for t in "${KERNEL_TESTS[@]}" "${QUANTIZED_GEMM_TESTS[@]}"; do
593+ IGNORES+=("--ignore=${t}")
594+ done
595+ python -m pytest backends/cuda/tests backends/cuda/passes/tests -v -o "addopts=" --durations=20 \
596+ "${IGNORES[@]}"
597+
598+ # Run Qwen 3.5 MoE tests (quantize roundtrip + TurboQuant KV cache + sampler)
599+ python -m pytest examples/models/qwen3_5_moe/test_quantize_roundtrip.py examples/models/qwen3_5_moe/test_turboquant.py examples/models/qwen3_5_moe/test_sampler.py -v -o "addopts="
600+
601+ # Run Gemma 4 31B tests (quant unit tests + pipeline integration tests)
602+ pip install gguf
603+ python -m pytest examples/models/gemma4_31b/tests/ --ignore=examples/models/gemma4_31b/tests/test_mlx_pipeline.py -v -o "addopts="
604+ fi
564605
565606 unittest-cuda-muse-glimmer-batching :
566607 name : unittest-cuda-muse-glimmer-batching
0 commit comments