Skip to content

fix: detect NVIDIA Jetson Orin boards instead of reporting CPU-only - #165

Closed
donghee-ai wants to merge 1 commit into
Andyyyy64:mainfrom
donghee-ai:feature/jetson-orin-detection
Closed

fix: detect NVIDIA Jetson Orin boards instead of reporting CPU-only#165
donghee-ai wants to merge 1 commit into
Andyyyy64:mainfrom
donghee-ai:feature/jetson-orin-detection

Conversation

@donghee-ai

Copy link
Copy Markdown

What

  • New hardware/jetson.py resolves the Jetson module from the kernel device tree.
  • hardware/nvidia.py treats the Tegra integrated GPU as unified memory and
    substitutes the resolved module name.
  • data/gpu.py gains bandwidth and compute-capability entries for Orin modules.
  • 43 tests, and a docs/hardware.md section.

Why

whichllm reports "No GPU detected — CPU-only mode" on every Jetson. On my
board it printed that while llama.cpp was serving Qwen3-8B on the same GPU.

Tegra is a unified-memory SoC with no dedicated VRAM, so the driver answers
NVML_ERROR_NOT_SUPPORTED for nvmlDeviceGetMemoryInfo, and nvidia-smi
prints [N/A] for memory.total — the same shape as DGX Spark / GB10, which
is already handled. But "Orin (nvgpu)" matches no unified-memory marker, so
both paths drop the GPU: the NVML branch re-raises, and the nvidia-smi
fallback finds no digits in [N/A] and continues.

That is not cosmetic — with no GPU every candidate is ranked cpu_only
(quality x0.50, sort -6.0, CPU speed heuristic), so the recommendations change
completely.

before   No GPU detected — CPU-only mode
after    Jetson Orin NX 16GB — 15.3 GB shared (CC 8.7, CUDA 12.6) — BW: 102 GB/s

A marker alone is not enough: estimate_tok_per_sec returns 0.0 without a
bandwidth, and every Orin module reports the same name — a 4 GB Orin Nano
(34 GB/s) and a 64 GB AGX Orin (204.8 GB/s) are both "Orin (nvgpu)". Same
"one name, several configurations" problem as the GTX 1650 GDDR5/GDDR6 split,
except clocks.max.memory is also NOT_SUPPORTED here. The device tree is the
remaining discriminator, and needs no root:

$ cat /proc/device-tree/compatible | tr '\0' '\n'
nvidia,p3768-0000+p3767-0000    # carrier board + module
nvidia,p3767-0000               # module
nvidia,tegra234                 # SoC generation

Only listed part numbers are claimed. An unrecognised module keeps its generic
name and resolves no bandwidth, rather than a product being guessed from an SoC
generation (tegra210 covers both Jetson Nano and TX1). Detection still
requires the driver to enumerate the GPU, so a board with a broken CUDA stack
keeps reporting none.

Testing

Jetson Orin NX 16GB (p3767-0000), JetPack 6.2.3 / L4T R36.5.0, nvpmodel MAXN,
llama.cpp CUDA a94d563, llama-bench -ngl 99 -p 512 -n 128 -fa 1 -r 3.

The bandwidth entry is what the measurements pin down. Sweeping candidate values
through estimate_tok_per_sec over four Q4_K_M models from 4.44 to 8.38 GiB
(one quantization, so the fit isolates bandwidth):

bandwidth MAPE
60.0 (read-kernel microbenchmark) 41.3%
68.0 (Orin Nano 8GB) 33.5%
102.4 (data sheet) 1.0%
136.5 (AGX Xavier) 33.6%
204.8 (AGX Orin) 100.4%

Per model at 102.4: EXAONE-3.5-7.8B 11.65 measured / 11.82 predicted,
Llama-3.1-8B 11.42 / 11.46, Qwen3-8B 11.14 / 11.22, Qwen3-14B 6.36 / 6.26 —
three unrelated families within 1.6%. Qwen3-8B reproduced at 11.14 tok/s in a
second session four days later. Runs were not thermally limited (tj peaked
77.5 C against a 99 C throttle) and did not swap.

  • Tests pass (pytest) — 527 passed (484 existing + 43 new), on 3.11/3.12/3.13
  • New tests added
  • Tested on real hardware
  • ruff check . / ruff format --check . clean

Notes

Scope is Orin only. Xavier and earlier stop at a JetPack that ships neither
a Tegra NVML nor a Tegra nvidia-smi, so no GPU name reaches this code there
and nothing I could add to a name-keyed table would fire. I left them out rather
than ship entries that cannot be reached.

That also means this does not overlap with #146, which is about Xavier. It
touches the same file but not _NVIDIA_UNIFIED_MEMORY_MARKERS, and the two
merge cleanly in either order — I checked.

Limits. One board. Only the Orin NX 16GB bandwidth is verified against
measured throughput; the other Orin entries are data-sheet values, annotated as
such in the code. I have no AGX Orin or Orin Nano to test on — they run the same
code path as the board I do have, with a different lookup key.

Left out deliberately. Below ~3 GiB of weights the estimate runs 34-42%
high, because achieved bandwidth on this board climbs with model size (39.8 GB/s
at 1.1 GB to 57.2 at 9.0 GB) while the formula treats it as constant. And MoE is
overestimated 2.4x for Qwen3-30B-A3B. Both are pre-existing, neither is
Jetson-specific, one board is not a basis for changing global constants, and
folding either into a detection fix would make this unreviewable. Happy to open
issues with the data if that is useful.

Tegra answers NVML_ERROR_NOT_SUPPORTED for nvmlDeviceGetMemoryInfo and
prints [N/A] for nvidia-smi memory.total, and "Orin (nvgpu)" matches no
unified-memory marker, so both detection paths dropped the GPU and every
candidate was ranked cpu_only.

Resolve the module from the kernel device tree, since every Orin module
reports the same driver name and Tegra supports neither the memory query
nor clocks.max.memory. Bandwidth for Jetson Orin NX 16GB is verified
against measured llama.cpp throughput; the other Orin entries are
data-sheet values.
@donghee-ai donghee-ai closed this by deleting the head repository Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant