Add Arm64 CPU Phase 1A CI bootstrap (#22123)
Co-authored-by: Ma Mingfei <mingfei.ma@intel.com>
This commit is contained in:
co-authored by
Ma Mingfei
parent
3c3f0bd55e
commit
55224fff08
@@ -0,0 +1,118 @@
|
|||||||
|
name: PR Test (Arm64)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
workflow_dispatch:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
ref:
|
||||||
|
description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
run_all_tests:
|
||||||
|
description: "Run all tests (for releasing or testing purpose)"
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: pr-test-arm64-${{ inputs.ref || github.ref }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-changes:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests}}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.ref || github.ref }}
|
||||||
|
|
||||||
|
- name: Determine run mode
|
||||||
|
id: run-mode
|
||||||
|
run: |
|
||||||
|
if [[ "${{ inputs.run_all_tests }}" == "true" ]]; then
|
||||||
|
echo "run_all_tests=true" >> $GITHUB_OUTPUT
|
||||||
|
echo "Run mode: ALL TESTS (run_all_tests=${{ inputs.run_all_tests }})"
|
||||||
|
else
|
||||||
|
echo "run_all_tests=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "Run mode: FILTERED (triggered by ${{ github.event_name }})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Detect file changes
|
||||||
|
id: filter
|
||||||
|
uses: dorny/paths-filter@v3
|
||||||
|
if: steps.run-mode.outputs.run_all_tests != 'true'
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
main_package:
|
||||||
|
- "python/sglang/!(multimodal_gen)/**/!(*.md)"
|
||||||
|
- "python/pyproject_cpu.toml"
|
||||||
|
- "test/**/!(*.md)"
|
||||||
|
- "sgl-kernel/**/*.!(md|txt)"
|
||||||
|
- ".github/workflows/pr-test-arm64.yml"
|
||||||
|
- "docker/arm64.Dockerfile"
|
||||||
|
|
||||||
|
pr-gate:
|
||||||
|
needs: check-changes
|
||||||
|
if: needs.check-changes.outputs.main_package == 'true'
|
||||||
|
uses: ./.github/workflows/pr-gate.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
build-test:
|
||||||
|
needs: [check-changes, pr-gate]
|
||||||
|
if: needs.check-changes.outputs.main_package == 'true'
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.ref || github.ref }}
|
||||||
|
|
||||||
|
- name: Build container
|
||||||
|
run: |
|
||||||
|
PR_REPO=${{ github.event.pull_request.head.repo.clone_url }}
|
||||||
|
PR_HEAD_REF=${{ github.head_ref }}
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
${PR_REPO:+--build-arg SGLANG_REPO=$PR_REPO} \
|
||||||
|
${PR_HEAD_REF:+--build-arg VER_SGLANG=$PR_HEAD_REF} \
|
||||||
|
. -f docker/arm64.Dockerfile -t sglang_arm64 --no-cache
|
||||||
|
|
||||||
|
- name: Run container
|
||||||
|
run: |
|
||||||
|
docker run -dt \
|
||||||
|
-v ${{ github.workspace }}:/sglang-checkout/ --ipc=host \
|
||||||
|
--name ci_sglang_arm64 \
|
||||||
|
sglang_arm64
|
||||||
|
|
||||||
|
- name: Arm sanity check
|
||||||
|
timeout-minutes: 5
|
||||||
|
run: |
|
||||||
|
docker exec -w /sglang-checkout/ ci_sglang_arm64 \
|
||||||
|
bash -c "source /opt/.venv/bin/activate && python3 -c 'import platform; import torch; import sgl_kernel; from sglang.srt.utils.common import is_host_cpu_arm64; assert platform.machine() in (\"aarch64\", \"arm64\"); assert is_host_cpu_arm64(); assert hasattr(torch.ops.sgl_kernel, \"decode_attention_cpu\"); assert hasattr(torch.ops.sgl_kernel, \"initialize\");'"
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
timeout-minutes: 36
|
||||||
|
run: |
|
||||||
|
docker exec -w /sglang-checkout/ ci_sglang_arm64 \
|
||||||
|
bash -c "source /opt/.venv/bin/activate && cd ./test/srt && python3 run_suite.py --suite per-commit-cpu-arm64 --timeout-per-file 1500"
|
||||||
|
|
||||||
|
- name: Change permission
|
||||||
|
timeout-minutes: 2
|
||||||
|
run: |
|
||||||
|
docker exec -u root ci_sglang_arm64 bash -c "
|
||||||
|
rm -rf /tmp/ci-home &&
|
||||||
|
chown -R $(id -u):$(id -g) /sglang-checkout/ 2>/dev/null || true
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Cleanup container
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker rm -f ci_sglang_arm64 || true
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
FROM ubuntu:24.04
|
||||||
|
SHELL ["/bin/bash", "-c"]
|
||||||
|
|
||||||
|
ARG SGLANG_REPO=https://github.com/sgl-project/sglang.git
|
||||||
|
ARG VER_SGLANG=main
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get full-upgrade -y && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
|
ca-certificates \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
vim \
|
||||||
|
gcc \
|
||||||
|
g++ \
|
||||||
|
make \
|
||||||
|
cmake \
|
||||||
|
libsqlite3-dev \
|
||||||
|
google-perftools \
|
||||||
|
libtbb-dev \
|
||||||
|
libnuma-dev \
|
||||||
|
numactl
|
||||||
|
|
||||||
|
WORKDIR /opt
|
||||||
|
|
||||||
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
||||||
|
source $HOME/.local/bin/env && \
|
||||||
|
uv venv --python 3.12
|
||||||
|
|
||||||
|
RUN echo -e '[[index]]\nname = "torch"\nurl = "https://download.pytorch.org/whl/cpu"\n\n[[index]]\nname = "torchvision"\nurl = "https://download.pytorch.org/whl/cpu"\n\n[[index]]\nname = "torchaudio"\nurl = "https://download.pytorch.org/whl/cpu"\n\n[[index]]\nname = "triton"\nurl = "https://download.pytorch.org/whl/cpu"' > .venv/uv.toml
|
||||||
|
|
||||||
|
ENV UV_CONFIG_FILE=/opt/.venv/uv.toml
|
||||||
|
ENV CMAKE_BUILD_PARALLEL_LEVEL=1
|
||||||
|
|
||||||
|
WORKDIR /sgl-workspace
|
||||||
|
RUN source $HOME/.local/bin/env && \
|
||||||
|
source /opt/.venv/bin/activate && \
|
||||||
|
git clone ${SGLANG_REPO} sglang && \
|
||||||
|
cd sglang && \
|
||||||
|
git checkout ${VER_SGLANG} && \
|
||||||
|
cd python && \
|
||||||
|
cp pyproject_cpu.toml pyproject.toml && \
|
||||||
|
uv pip install . && \
|
||||||
|
cd ../sgl-kernel && \
|
||||||
|
cp pyproject_cpu.toml pyproject.toml && \
|
||||||
|
uv pip install .
|
||||||
|
|
||||||
|
ENV SGLANG_USE_CPU_ENGINE=1
|
||||||
|
RUN echo 'source /opt/.venv/bin/activate' >> /root/.bashrc
|
||||||
|
|
||||||
|
WORKDIR /sgl-workspace/sglang
|
||||||
@@ -51,6 +51,7 @@ from sglang.srt.utils.common import (
|
|||||||
is_flashinfer_available,
|
is_flashinfer_available,
|
||||||
is_hip,
|
is_hip,
|
||||||
is_hopper_with_cuda_12_3,
|
is_hopper_with_cuda_12_3,
|
||||||
|
is_host_cpu_arm64,
|
||||||
is_mps,
|
is_mps,
|
||||||
is_musa,
|
is_musa,
|
||||||
is_no_spec_infer_or_topk_one,
|
is_no_spec_infer_or_topk_one,
|
||||||
@@ -1203,7 +1204,9 @@ class ServerArgs:
|
|||||||
def _handle_cpu_backends(self):
|
def _handle_cpu_backends(self):
|
||||||
if self.device == "cpu":
|
if self.device == "cpu":
|
||||||
if self.attention_backend is None:
|
if self.attention_backend is None:
|
||||||
self.attention_backend = "intel_amx"
|
self.attention_backend = (
|
||||||
|
"torch_native" if is_host_cpu_arm64() else "intel_amx"
|
||||||
|
)
|
||||||
self.sampling_backend = "pytorch"
|
self.sampling_backend = "pytorch"
|
||||||
|
|
||||||
def _handle_npu_backends(self):
|
def _handle_npu_backends(self):
|
||||||
|
|||||||
@@ -75,6 +75,23 @@ endif()
|
|||||||
|
|
||||||
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
|
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
|
||||||
|
|
||||||
|
# These kernels still rely on x86-specific AMX/AVX512 implementations.
|
||||||
|
# Keep them out of Arm64 bootstrap builds until native Arm paths land.
|
||||||
|
set(SGLANG_CPU_X86_ONLY_SOURCES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/gemm_int4.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/moe.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/moe_fp8.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/moe_int4.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/moe_int8.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/qkv_proj.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mamba/conv.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
|
||||||
|
add_compile_definitions(SGLANG_CPU_ARM64_SKIP_X86_ONLY_OPS)
|
||||||
|
list(REMOVE_ITEM SOURCES ${SGLANG_CPU_X86_ONLY_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT DEFINED ENV{SGLANG_CPU_FP8_CVT_FTZ})
|
if(NOT DEFINED ENV{SGLANG_CPU_FP8_CVT_FTZ})
|
||||||
set(ENV{SGLANG_CPU_FP8_CVT_FTZ} "1")
|
set(ENV{SGLANG_CPU_FP8_CVT_FTZ} "1")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -150,18 +150,6 @@ at::Tensor convert_scale_packed(at::Tensor& scale);
|
|||||||
// quant
|
// quant
|
||||||
std::tuple<at::Tensor, at::Tensor> per_token_quant_int8_cpu(at::Tensor& A);
|
std::tuple<at::Tensor, at::Tensor> per_token_quant_int8_cpu(at::Tensor& A);
|
||||||
|
|
||||||
// gemm
|
|
||||||
at::Tensor
|
|
||||||
weight_packed_linear(at::Tensor& mat1, at::Tensor& mat2, const std::optional<at::Tensor>& bias, bool is_vnni);
|
|
||||||
|
|
||||||
// gemm fusion
|
|
||||||
at::Tensor fused_linear_sigmoid_mul(
|
|
||||||
at::Tensor& mat1,
|
|
||||||
at::Tensor& mat2,
|
|
||||||
const std::optional<at::Tensor>& bias,
|
|
||||||
bool is_vnni,
|
|
||||||
const at::Tensor& post_mul_mat);
|
|
||||||
|
|
||||||
// igemm
|
// igemm
|
||||||
at::Tensor int8_scaled_mm_cpu(
|
at::Tensor int8_scaled_mm_cpu(
|
||||||
at::Tensor& mat1,
|
at::Tensor& mat1,
|
||||||
@@ -195,6 +183,7 @@ at::Tensor int8_scaled_mm_with_quant(
|
|||||||
at::ScalarType out_dtype,
|
at::ScalarType out_dtype,
|
||||||
bool is_vnni);
|
bool is_vnni);
|
||||||
|
|
||||||
|
#if !defined(SGLANG_CPU_ARM64_SKIP_X86_ONLY_OPS)
|
||||||
// int4 gemm
|
// int4 gemm
|
||||||
at::Tensor int4_scaled_mm_cpu(
|
at::Tensor int4_scaled_mm_cpu(
|
||||||
at::Tensor& x, at::Tensor& w, at::Tensor& w_zeros, at::Tensor& w_scales, std::optional<at::Tensor> bias);
|
at::Tensor& x, at::Tensor& w, at::Tensor& w_zeros, at::Tensor& w_scales, std::optional<at::Tensor> bias);
|
||||||
@@ -205,10 +194,24 @@ std::tuple<at::Tensor, at::Tensor, at::Tensor> convert_weight_packed_scale_zp(
|
|||||||
at::Tensor qzeros, // awq: (*, K / group_size, N / 8) || gptq: (*, K / group_size, N / 8) , int32
|
at::Tensor qzeros, // awq: (*, K / group_size, N / 8) || gptq: (*, K / group_size, N / 8) , int32
|
||||||
at::Tensor scales, // awq: (*, K / group_size, N) || gptq: (*, K / group_size, N) , bfloat16
|
at::Tensor scales, // awq: (*, K / group_size, N) || gptq: (*, K / group_size, N) , bfloat16
|
||||||
int64_t quant_method_4bit);
|
int64_t quant_method_4bit);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// gemm
|
||||||
|
at::Tensor
|
||||||
|
weight_packed_linear(at::Tensor& mat1, at::Tensor& mat2, const std::optional<at::Tensor>& bias, bool is_vnni);
|
||||||
|
|
||||||
|
// gemm fusion
|
||||||
|
at::Tensor fused_linear_sigmoid_mul(
|
||||||
|
at::Tensor& mat1,
|
||||||
|
at::Tensor& mat2,
|
||||||
|
const std::optional<at::Tensor>& bias,
|
||||||
|
bool is_vnni,
|
||||||
|
const at::Tensor& post_mul_mat);
|
||||||
|
|
||||||
// bmm
|
// bmm
|
||||||
void bmm_cpu(at::Tensor& out, at::Tensor& mat1, at::Tensor& mat2, bool is_vnni, const std::optional<at::Tensor>& scale);
|
void bmm_cpu(at::Tensor& out, at::Tensor& mat1, at::Tensor& mat2, bool is_vnni, const std::optional<at::Tensor>& scale);
|
||||||
|
|
||||||
|
#if !defined(SGLANG_CPU_ARM64_SKIP_X86_ONLY_OPS)
|
||||||
// fused moe
|
// fused moe
|
||||||
at::Tensor fused_experts_cpu(
|
at::Tensor fused_experts_cpu(
|
||||||
at::Tensor& hidden_states,
|
at::Tensor& hidden_states,
|
||||||
@@ -306,6 +309,7 @@ at::Tensor causal_conv1d_update_cpu(
|
|||||||
const std::optional<at::Tensor>& conv_state_indices,
|
const std::optional<at::Tensor>& conv_state_indices,
|
||||||
int64_t pad_slot_id,
|
int64_t pad_slot_id,
|
||||||
bool is_vnni);
|
bool is_vnni);
|
||||||
|
#endif
|
||||||
|
|
||||||
// conv3d fast path for patch embedding
|
// conv3d fast path for patch embedding
|
||||||
at::Tensor conv3d_embed_weight_pack(const at::Tensor& weight);
|
at::Tensor conv3d_embed_weight_pack(const at::Tensor& weight);
|
||||||
@@ -495,15 +499,6 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
|
|||||||
m.def("per_token_quant_int8_cpu(Tensor A) -> (Tensor, Tensor)");
|
m.def("per_token_quant_int8_cpu(Tensor A) -> (Tensor, Tensor)");
|
||||||
m.impl("per_token_quant_int8_cpu", torch::kCPU, &per_token_quant_int8_cpu);
|
m.impl("per_token_quant_int8_cpu", torch::kCPU, &per_token_quant_int8_cpu);
|
||||||
|
|
||||||
// gemm
|
|
||||||
m.def("weight_packed_linear(Tensor mat1, Tensor mat2, Tensor? bias, bool is_vnni) -> Tensor");
|
|
||||||
m.impl("weight_packed_linear", torch::kCPU, &weight_packed_linear);
|
|
||||||
|
|
||||||
// gemm fusion
|
|
||||||
m.def(
|
|
||||||
"fused_linear_sigmoid_mul(Tensor mat1, Tensor mat2, Tensor? bias, bool is_vnni, Tensor post_mul_mat) -> Tensor");
|
|
||||||
m.impl("fused_linear_sigmoid_mul", torch::kCPU, &fused_linear_sigmoid_mul);
|
|
||||||
|
|
||||||
// igemm
|
// igemm
|
||||||
m.def(
|
m.def(
|
||||||
"int8_scaled_mm_cpu(Tensor mat1, Tensor mat2, Tensor scales1, Tensor scales2, Tensor? bias, ScalarType "
|
"int8_scaled_mm_cpu(Tensor mat1, Tensor mat2, Tensor scales1, Tensor scales2, Tensor? bias, ScalarType "
|
||||||
@@ -526,6 +521,7 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
|
|||||||
"is_vnni) -> Tensor");
|
"is_vnni) -> Tensor");
|
||||||
m.impl("int8_scaled_mm_with_quant", torch::kCPU, &int8_scaled_mm_with_quant);
|
m.impl("int8_scaled_mm_with_quant", torch::kCPU, &int8_scaled_mm_with_quant);
|
||||||
|
|
||||||
|
#if !defined(SGLANG_CPU_ARM64_SKIP_X86_ONLY_OPS)
|
||||||
// int4 gemm
|
// int4 gemm
|
||||||
m.def("int4_scaled_mm_cpu(Tensor x, Tensor w, Tensor w_zeros, Tensor w_scales, Tensor? bias) -> Tensor");
|
m.def("int4_scaled_mm_cpu(Tensor x, Tensor w, Tensor w_zeros, Tensor w_scales, Tensor? bias) -> Tensor");
|
||||||
m.impl("int4_scaled_mm_cpu", torch::kCPU, &int4_scaled_mm_cpu);
|
m.impl("int4_scaled_mm_cpu", torch::kCPU, &int4_scaled_mm_cpu);
|
||||||
@@ -535,11 +531,22 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
|
|||||||
"convert_weight_packed_scale_zp(Tensor weight, Tensor qzeros, Tensor scales, int quant_method_4bit) -> (Tensor, "
|
"convert_weight_packed_scale_zp(Tensor weight, Tensor qzeros, Tensor scales, int quant_method_4bit) -> (Tensor, "
|
||||||
"Tensor, Tensor)");
|
"Tensor, Tensor)");
|
||||||
m.impl("convert_weight_packed_scale_zp", torch::kCPU, &convert_weight_packed_scale_zp);
|
m.impl("convert_weight_packed_scale_zp", torch::kCPU, &convert_weight_packed_scale_zp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// gemm
|
||||||
|
m.def("weight_packed_linear(Tensor mat1, Tensor mat2, Tensor? bias, bool is_vnni) -> Tensor");
|
||||||
|
m.impl("weight_packed_linear", torch::kCPU, &weight_packed_linear);
|
||||||
|
|
||||||
|
// gemm fusion
|
||||||
|
m.def(
|
||||||
|
"fused_linear_sigmoid_mul(Tensor mat1, Tensor mat2, Tensor? bias, bool is_vnni, Tensor post_mul_mat) -> Tensor");
|
||||||
|
m.impl("fused_linear_sigmoid_mul", torch::kCPU, &fused_linear_sigmoid_mul);
|
||||||
|
|
||||||
// bmm
|
// bmm
|
||||||
m.def("bmm_cpu(Tensor(a!) out, Tensor mat1, Tensor mat2, bool is_vnni, Tensor? scale) -> ()");
|
m.def("bmm_cpu(Tensor(a!) out, Tensor mat1, Tensor mat2, bool is_vnni, Tensor? scale) -> ()");
|
||||||
m.impl("bmm_cpu", torch::kCPU, &bmm_cpu);
|
m.impl("bmm_cpu", torch::kCPU, &bmm_cpu);
|
||||||
|
|
||||||
|
#if !defined(SGLANG_CPU_ARM64_SKIP_X86_ONLY_OPS)
|
||||||
// moe
|
// moe
|
||||||
m.def(
|
m.def(
|
||||||
"fused_experts_cpu(Tensor hidden_states, Tensor w1, Tensor w2, Tensor topk_weights, Tensor topk_ids, bool "
|
"fused_experts_cpu(Tensor hidden_states, Tensor w1, Tensor w2, Tensor topk_weights, Tensor topk_ids, bool "
|
||||||
@@ -585,6 +592,7 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
|
|||||||
"causal_conv1d_update_cpu(Tensor x, Tensor(a!) conv_states, Tensor weight, Tensor? bias, bool silu_activation,"
|
"causal_conv1d_update_cpu(Tensor x, Tensor(a!) conv_states, Tensor weight, Tensor? bias, bool silu_activation,"
|
||||||
"Tensor? cache_seqlens, Tensor? conv_state_indices, int pad_slot_id, bool is_vnni) -> Tensor");
|
"Tensor? cache_seqlens, Tensor? conv_state_indices, int pad_slot_id, bool is_vnni) -> Tensor");
|
||||||
m.impl("causal_conv1d_update_cpu", torch::kCPU, &causal_conv1d_update_cpu);
|
m.impl("causal_conv1d_update_cpu", torch::kCPU, &causal_conv1d_update_cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
// conv3d fast path for patch embedding
|
// conv3d fast path for patch embedding
|
||||||
m.def("conv3d_embed_weight_pack(Tensor weight) -> Tensor");
|
m.def("conv3d_embed_weight_pack(Tensor weight) -> Tensor");
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from sglang.srt.server_args import ServerArgs
|
||||||
|
|
||||||
|
|
||||||
|
class TestServerArgsCPUBackend(unittest.TestCase):
|
||||||
|
def _make_server_args(self, attention_backend=None):
|
||||||
|
server_args = ServerArgs.__new__(ServerArgs)
|
||||||
|
server_args.device = "cpu"
|
||||||
|
server_args.attention_backend = attention_backend
|
||||||
|
server_args.sampling_backend = None
|
||||||
|
return server_args
|
||||||
|
|
||||||
|
@patch("sglang.srt.server_args.is_host_cpu_arm64", return_value=True)
|
||||||
|
def test_arm_cpu_defaults_to_torch_native(self, _mock_is_arm64):
|
||||||
|
server_args = self._make_server_args()
|
||||||
|
|
||||||
|
ServerArgs._handle_cpu_backends(server_args)
|
||||||
|
|
||||||
|
self.assertEqual(server_args.attention_backend, "torch_native")
|
||||||
|
self.assertEqual(server_args.sampling_backend, "pytorch")
|
||||||
|
|
||||||
|
@patch("sglang.srt.server_args.is_host_cpu_arm64", return_value=False)
|
||||||
|
def test_x86_cpu_defaults_to_intel_amx(self, _mock_is_arm64):
|
||||||
|
server_args = self._make_server_args()
|
||||||
|
|
||||||
|
ServerArgs._handle_cpu_backends(server_args)
|
||||||
|
|
||||||
|
self.assertEqual(server_args.attention_backend, "intel_amx")
|
||||||
|
self.assertEqual(server_args.sampling_backend, "pytorch")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -44,6 +44,21 @@ suite_amd = {
|
|||||||
# by test/run_suite.py using the registry system.
|
# by test/run_suite.py using the registry system.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Keep the Arm64 bootstrap suite limited to hosted-runner-safe unit kernels.
|
||||||
|
# `test_extend.py`, `test_mamba.py`, and `test_mla.py` still hit the
|
||||||
|
# x86-specific BF16 BRGEMM/VNNI path on Arm and need dedicated fallbacks.
|
||||||
|
suite_arm64 = {
|
||||||
|
"per-commit-cpu-arm64": [
|
||||||
|
TestFile("cpu/test_activation.py"),
|
||||||
|
TestFile("cpu/test_decode.py"),
|
||||||
|
TestFile("cpu/test_norm.py"),
|
||||||
|
TestFile("cpu/test_qwen3.py"),
|
||||||
|
TestFile("cpu/test_rope.py"),
|
||||||
|
TestFile("cpu/test_server_args_backend.py"),
|
||||||
|
TestFile("cpu/test_topk.py"),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
# Add Intel Xeon tests
|
# Add Intel Xeon tests
|
||||||
suite_xeon = {
|
suite_xeon = {
|
||||||
"per-commit-cpu": [
|
"per-commit-cpu": [
|
||||||
@@ -66,6 +81,7 @@ suite_xeon = {
|
|||||||
TestFile("cpu/test_qkv_proj_with_rope.py"),
|
TestFile("cpu/test_qkv_proj_with_rope.py"),
|
||||||
TestFile("cpu/test_qwen3.py"),
|
TestFile("cpu/test_qwen3.py"),
|
||||||
TestFile("cpu/test_rope.py"),
|
TestFile("cpu/test_rope.py"),
|
||||||
|
TestFile("cpu/test_server_args_backend.py"),
|
||||||
TestFile("cpu/test_shared_expert.py"),
|
TestFile("cpu/test_shared_expert.py"),
|
||||||
TestFile("cpu/test_topk.py"),
|
TestFile("cpu/test_topk.py"),
|
||||||
],
|
],
|
||||||
@@ -83,6 +99,7 @@ suite_xpu = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suites.update(suite_amd)
|
suites.update(suite_amd)
|
||||||
|
suites.update(suite_arm64)
|
||||||
suites.update(suite_xeon)
|
suites.update(suite_xeon)
|
||||||
suites.update(suite_xpu)
|
suites.update(suite_xpu)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user