Skip to content

Commit dcbfbae

Browse files
feat: add SM87 and SM110 compute capability support for Jetson devices
- Add (87, 87) and (110, 110) match arms in compute_cap.rs for dedicated Jetson Orin (SM87) and Jetson Thor (SM110) binary support - Add Dockerfile-jetson: multi-target Dockerfile building both SM87 and SM110 binaries with architecture-aware sccache for aarch64/x86_64 - Add jetson-entrypoint.sh: runtime GPU detection and routing to the correct binary based on compute capability - Add comprehensive test coverage for SM87 and SM110 cross-compatibility
1 parent f016879 commit dcbfbae

3 files changed

Lines changed: 179 additions & 0 deletions

File tree

Dockerfile-jetson

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
FROM nvidia/cuda:12.9.1-devel-ubuntu24.04 AS base-builder
2+
3+
ENV SCCACHE=0.10.0
4+
ENV RUSTC_WRAPPER=/usr/local/bin/sccache
5+
ENV PATH="/root/.cargo/bin:${PATH}"
6+
# aligned with `cargo-chef` version in `lukemathwalker/cargo-chef:latest-rust-1.92-bookworm`
7+
ENV CARGO_CHEF=0.1.73
8+
9+
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
10+
curl \
11+
libssl-dev \
12+
pkg-config \
13+
&& rm -rf /var/lib/apt/lists/*
14+
15+
# Download and configure sccache (detect architecture for Jetson aarch64 support)
16+
RUN ARCH=$(uname -m) && \
17+
if [ "$ARCH" = "aarch64" ]; then SCCACHE_TARGET="aarch64-unknown-linux-musl"; \
18+
else SCCACHE_TARGET="x86_64-unknown-linux-musl"; fi && \
19+
curl -fsSL https://github.com/mozilla/sccache/releases/download/v$SCCACHE/sccache-v$SCCACHE-$SCCACHE_TARGET.tar.gz | tar -xzv --strip-components=1 -C /usr/local/bin sccache-v$SCCACHE-$SCCACHE_TARGET/sccache && \
20+
chmod +x /usr/local/bin/sccache
21+
22+
COPY rust-toolchain.toml rust-toolchain.toml
23+
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
24+
RUN cargo install cargo-chef --version $CARGO_CHEF --locked
25+
26+
FROM base-builder AS planner
27+
28+
WORKDIR /usr/src
29+
30+
COPY backends backends
31+
COPY core core
32+
COPY router router
33+
COPY Cargo.toml ./
34+
COPY Cargo.lock ./
35+
36+
RUN cargo chef prepare --recipe-path recipe.json
37+
38+
FROM base-builder AS builder
39+
40+
ARG GIT_SHA
41+
ARG DOCKER_LABEL
42+
43+
# sccache specific variables
44+
ARG SCCACHE_GHA_ENABLED
45+
46+
# Limit parallelism
47+
ARG RAYON_NUM_THREADS=4
48+
ARG CARGO_BUILD_JOBS
49+
ARG CARGO_BUILD_INCREMENTAL
50+
51+
WORKDIR /usr/src
52+
53+
COPY --from=planner /usr/src/recipe.json recipe.json
54+
55+
RUN --mount=type=secret,id=actions_results_url,env=ACTIONS_RESULTS_URL \
56+
--mount=type=secret,id=actions_runtime_token,env=ACTIONS_RUNTIME_TOKEN \
57+
cargo chef cook --release --recipe-path recipe.json && sccache -s;
58+
59+
RUN --mount=type=secret,id=actions_results_url,env=ACTIONS_RESULTS_URL \
60+
--mount=type=secret,id=actions_runtime_token,env=ACTIONS_RUNTIME_TOKEN \
61+
CUDA_COMPUTE_CAP=87 cargo chef cook --release --features candle-cuda --recipe-path recipe.json && sccache -s;
62+
63+
RUN --mount=type=secret,id=actions_results_url,env=ACTIONS_RESULTS_URL \
64+
--mount=type=secret,id=actions_runtime_token,env=ACTIONS_RUNTIME_TOKEN \
65+
CUDA_COMPUTE_CAP=110 cargo chef cook --release --features candle-cuda --recipe-path recipe.json && sccache -s;
66+
67+
COPY backends backends
68+
COPY core core
69+
COPY router router
70+
COPY Cargo.toml ./
71+
COPY Cargo.lock ./
72+
73+
RUN --mount=type=secret,id=actions_results_url,env=ACTIONS_RESULTS_URL \
74+
--mount=type=secret,id=actions_runtime_token,env=ACTIONS_RUNTIME_TOKEN \
75+
CUDA_COMPUTE_CAP=87 cargo build --release --bin text-embeddings-router -F candle-cuda && sccache -s;
76+
77+
RUN mv /usr/src/target/release/text-embeddings-router /usr/src/target/release/text-embeddings-router-87
78+
79+
RUN --mount=type=secret,id=actions_results_url,env=ACTIONS_RESULTS_URL \
80+
--mount=type=secret,id=actions_runtime_token,env=ACTIONS_RUNTIME_TOKEN \
81+
CUDA_COMPUTE_CAP=110 cargo build --release --bin text-embeddings-router -F candle-cuda && sccache -s;
82+
83+
RUN mv /usr/src/target/release/text-embeddings-router /usr/src/target/release/text-embeddings-router-110
84+
85+
FROM nvidia/cuda:12.9.1-runtime-ubuntu24.04 AS base
86+
87+
ARG DEFAULT_USE_FLASH_ATTENTION=True
88+
89+
ENV HUGGINGFACE_HUB_CACHE=/data \
90+
PORT=80 \
91+
USE_FLASH_ATTENTION=$DEFAULT_USE_FLASH_ATTENTION \
92+
LD_LIBRARY_PATH="/usr/local/cuda/lib64:${LD_LIBRARY_PATH}"
93+
94+
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
95+
ca-certificates \
96+
libssl-dev \
97+
curl \
98+
cuda-compat-12-9 \
99+
&& rm -rf /var/lib/apt/lists/*
100+
101+
COPY --from=builder /usr/src/target/release/text-embeddings-router-87 /usr/local/bin/text-embeddings-router-87
102+
COPY --from=builder /usr/src/target/release/text-embeddings-router-110 /usr/local/bin/text-embeddings-router-110
103+
104+
COPY --chmod=775 jetson-entrypoint.sh entrypoint.sh
105+
106+
ENTRYPOINT ["./entrypoint.sh"]
107+
CMD ["--json-output"]

backends/candle/src/compute_cap.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ fn compute_cap_matching(runtime_compute_cap: usize, compile_compute_cap: usize)
2828
(75, 75) => true,
2929
(80..=89, 80) => true,
3030
(86..=89, 80..=86) => true,
31+
(87, 87) => true,
3132
(89, 89) => true,
3233
(90, 90) => true,
3334
(100, 100) => true,
35+
(110, 110) => true,
3436
(120, 120) => true,
3537
(_, _) => false,
3638
}
@@ -54,47 +56,79 @@ mod tests {
5456
assert!(compute_cap_matching(75, 75));
5557
assert!(compute_cap_matching(80, 80));
5658
assert!(compute_cap_matching(86, 86));
59+
assert!(compute_cap_matching(87, 87));
5760
assert!(compute_cap_matching(89, 89));
5861
assert!(compute_cap_matching(90, 90));
62+
assert!(compute_cap_matching(110, 110));
5963
assert!(compute_cap_matching(120, 120));
6064

6165
assert!(compute_cap_matching(86, 80));
66+
assert!(compute_cap_matching(87, 80));
6267
assert!(compute_cap_matching(89, 80));
68+
assert!(compute_cap_matching(87, 86));
6369
assert!(compute_cap_matching(89, 86));
6470

6571
assert!(!compute_cap_matching(75, 80));
6672
assert!(!compute_cap_matching(75, 86));
73+
assert!(!compute_cap_matching(75, 87));
6774
assert!(!compute_cap_matching(75, 89));
6875
assert!(!compute_cap_matching(75, 90));
76+
assert!(!compute_cap_matching(75, 110));
6977

7078
assert!(!compute_cap_matching(80, 75));
7179
assert!(!compute_cap_matching(80, 86));
80+
assert!(!compute_cap_matching(80, 87));
7281
assert!(!compute_cap_matching(80, 89));
7382
assert!(!compute_cap_matching(80, 90));
83+
assert!(!compute_cap_matching(80, 110));
7484

7585
assert!(!compute_cap_matching(86, 75));
86+
assert!(!compute_cap_matching(86, 87));
7687
assert!(!compute_cap_matching(86, 89));
7788
assert!(!compute_cap_matching(86, 90));
89+
assert!(!compute_cap_matching(86, 110));
90+
91+
assert!(!compute_cap_matching(87, 75));
92+
assert!(!compute_cap_matching(87, 89));
93+
assert!(!compute_cap_matching(87, 90));
94+
assert!(!compute_cap_matching(87, 110));
7895

7996
assert!(!compute_cap_matching(89, 75));
97+
assert!(!compute_cap_matching(89, 87));
8098
assert!(!compute_cap_matching(89, 90));
99+
assert!(!compute_cap_matching(89, 110));
81100

82101
assert!(!compute_cap_matching(90, 75));
83102
assert!(!compute_cap_matching(90, 80));
84103
assert!(!compute_cap_matching(90, 86));
104+
assert!(!compute_cap_matching(90, 87));
85105
assert!(!compute_cap_matching(90, 89));
106+
assert!(!compute_cap_matching(90, 110));
86107

87108
assert!(!compute_cap_matching(100, 75));
88109
assert!(!compute_cap_matching(100, 80));
89110
assert!(!compute_cap_matching(100, 86));
111+
assert!(!compute_cap_matching(100, 87));
90112
assert!(!compute_cap_matching(100, 89));
91113
assert!(!compute_cap_matching(100, 90));
114+
assert!(!compute_cap_matching(100, 110));
92115

93116
assert!(!compute_cap_matching(120, 75));
94117
assert!(!compute_cap_matching(120, 80));
95118
assert!(!compute_cap_matching(120, 86));
119+
assert!(!compute_cap_matching(120, 87));
96120
assert!(!compute_cap_matching(120, 89));
97121
assert!(!compute_cap_matching(120, 90));
98122
assert!(!compute_cap_matching(120, 100));
123+
assert!(!compute_cap_matching(120, 110));
124+
125+
assert!(!compute_cap_matching(110, 75));
126+
assert!(!compute_cap_matching(110, 80));
127+
assert!(!compute_cap_matching(110, 86));
128+
assert!(!compute_cap_matching(110, 87));
129+
assert!(!compute_cap_matching(110, 89));
130+
assert!(!compute_cap_matching(110, 90));
131+
assert!(!compute_cap_matching(110, 100));
132+
assert!(!compute_cap_matching(110, 120));
99133
}
100134
}

jetson-entrypoint.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/bash
2+
3+
if ! command -v nvidia-smi &>/dev/null; then
4+
echo "Error: 'nvidia-smi' command not found."
5+
exit 1
6+
fi
7+
8+
# NOTE: Given that we need to support CUDA versions earlier than CUDA 12.9.1, we
9+
# need to include the `cuda-compat-12-9` in `LD_LIBRARY_PATH` when the host CUDA
10+
# version is lower than that; whilst we shouldn't include that when CUDA is 13.0+
11+
# as otherwise it will fail due to it.
12+
if [ -d /usr/local/cuda/compat ]; then
13+
DRIVER_CUDA=$(nvidia-smi 2>/dev/null | awk '/CUDA Version/ {print $3; exit}')
14+
15+
IFS='.' read -r MAJ MIN PATCH <<EOF
16+
${DRIVER_CUDA:-0.0.0}
17+
EOF
18+
: "${MIN:=0}"
19+
: "${PATCH:=0}"
20+
21+
DRIVER_INT=$((10#${MAJ} * 10000 + 10#${MIN} * 100 + 10#${PATCH}))
22+
TARGET_INT=$((12 * 10000 + 9 * 100 + 1))
23+
24+
if [ "$DRIVER_INT" -lt "$TARGET_INT" ]; then
25+
export LD_LIBRARY_PATH="/usr/local/cuda/compat:${LD_LIBRARY_PATH}"
26+
fi
27+
fi
28+
29+
compute_cap=$(nvidia-smi --query-gpu=compute_cap --format=csv | sed -n '2p' | sed 's/\.//g')
30+
31+
if [ ${compute_cap} -eq 87 ]; then
32+
exec text-embeddings-router-87 "$@"
33+
elif [ ${compute_cap} -eq 110 ]; then
34+
exec text-embeddings-router-110 "$@"
35+
else
36+
echo "cuda compute cap ${compute_cap} is not supported by the Jetson image (supported: 87, 110)"
37+
exit 1
38+
fi

0 commit comments

Comments
 (0)