![]() | ![]() | ![]() | ![]() |
Abstract
I spent almost a year developing a project that made llama.cpp easy to use, and implemented some pretty wacky math to get multi-GPU balancing as close to OOM‘ing as possible (I paid for the VRAM, I’m gonna use all the VRAM). Then Unsloth released Studio. I was hesitant to try it, because so much crap is being made that I’ve just had vibe-slop-overload.
But then I tried it. Damn! It’s does everything, and well. So I set mine on fire, and decided to let someone else maintain a complicated pile of bits.
I chose openSUSE Tumbleweed because I have strong feelings for openSUSE, and Leap‘s kernel is too old for these GPUs.
My system has two Intel Arc B60 GPUs (I like a challenge) – but this guide should apply to any in the Battlemage (Xe2) architecture.
NOTE: There is a quirk that I call the Intel ECC VRAM Robbery Scheme. Basically, Intel skims a little VRAM off the top to pay for ECC operations. ECC is great for lots of things, and other vendors handle it better. See the end of this guide for a workaround.
Be advised that I jump around logically. These guides are my progress notes, and I often have to go back and re-write whole sections as a result of failures or sub-optimal results. Pick and choose what matters to you, but I recommend you go the intellectually curious route and play the whole game <3
- Abstract
- Install and Ready the Operating Environment
- Install the Native Intel Level Zero Compute Driver
- Intel oneAPI DPC++ Library (oneDPL) / SYCL
- Vulkan
- Unsloth Studio
- SYCL vs Vulkan
- Intel ECC VRAM Robbery Scheme – Work Around
- But What About SYCL?
- Things I Broke So You Don’t Have To (Landmines & Guardrails)
- Helpful Links
Install and Ready the Operating Environment
Do a “Server” installation of openSUSE Tumbleweed. Pretty simple. From there, the adventure begins.
First, we need to verify that the GPU(s) are properly detected:
beaker@SAL9000:~> lspci -Dnnk | grep -A3 Battlemage
0000:01:00.0 VGA compatible controller [0300]: Intel Corporation Battlemage G21 [Arc Pro B60] [8086:e211]
Subsystem: Device [207e:a023]
Kernel driver in use: xe
Kernel modules: xe
0000:02:00.0 VGA compatible controller [0300]: Intel Corporation Battlemage G21 [Arc Pro B60] [8086:e211]
Subsystem: Device [207e:a023]
Kernel driver in use: xe
Kernel modules: xe
beaker@SAL9000:~> ls -l /dev/dri/renderD*
crw-rw----. 1 root render 226, 128 Aug 31 17:03 /dev/dri/renderD128
crw-rw----. 1 root render 226, 129 Aug 31 17:03 /dev/dri/renderD129
beaker@SAL9000:~> lsmod | grep '^xe'
xe 4493312 2
Install the Native Intel Level Zero Compute Driver
beaker@SAL9000:~> sudo zypper --non-interactive install level-zero level-zero-devel libze_intel_gpu1 libze_intel_gpu_raytracing intel-gpu-tools clinfo intel-opencl
You’ll also need to give your user GPU access. This one keeps biting me, because I usually just YOLO as root:
beaker@SAL9000:~> sudo usermod -aG render,video "$USER"
Don’t forget to logout and back in for this to take affect. Then this command should work for you:
beaker@SAL9000:~> clinfo -l
Platform #0: Intel(R) OpenCL Graphics
+-- Device #0: Intel(R) Arc(TM) Pro B60 Graphics
`-- Device #1: Intel(R) Arc(TM) Pro B60 Graphics
Intel oneAPI DPC++ Library (oneDPL) / SYCL
Right now, only the OpenCL side of the compute-runtime stack is working. Now for the fun stuff.
On the Linux side, Intel seems to only love Ubuntu – which is odd, because Ubuntu is Debian made shitty. But I digress…
We’re going to be doing some manual labor here, but we like that! First, the prerequisites:
beaker@SAL9000:~> sudo zypper --non-interactive install -t pattern devel_C_C++
beaker@SAL9000:~> sudo zypper --non-interactive install cmake
Next add Intel’s oneAPI repo (separate from Tumbleweed’s own repos… this is Intel’s official YUM-style repo, which works fine with zypper):
beaker@SAL9000:~> sudo rpm --import https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
beaker@SAL9000:~> sudo zypper addrepo https://yum.repos.intel.com/oneapi oneAPI
beaker@SAL9000:~> sudo zypper refresh
Now, install and activate the DPC++/C++ compiler + SYCL runtime. This installs to /opt/intel/oneapi, fully separate from the libze_intel_gpu1/level-zero packages from Tumbleweed’s repo we already have. No conflicts, they weirdly coexist fine. Note that we need to source the environment as well. This feels hacky, because it is:
beaker@SAL9000:~> sudo zypper --non-interactive install intel-oneapi-compiler-dpcpp-cpp intel-oneapi-mkl-devel
beaker@SAL9000:~> source /opt/intel/oneapi/setvars.sh
:: initializing oneAPI environment ...
-bash: BASH_VERSION = 5.3.15(1)-release
args: Using "$@" for setvars.sh arguments:
:: compiler -- latest
:: debugger -- latest
:: dev-utilities -- latest
:: dpl -- latest
:: tbb -- latest
:: tcm -- latest
:: umf -- latest
:: oneAPI environment initialized ::
Tip: If you don’t want to source that
setvars.shevery time you want to work with those tools, run this to modify your PATH in.bashrc:
beaker@SAL9000:~> cat >> ~/.bashrc << 'EOF'
# Intel oneAPI environment (for xpu-smi / SYCL / icpx toolchain)
if [ -f /opt/intel/oneapi/setvars.sh ]; then
source /opt/intel/oneapi/setvars.sh > /dev/null 2>&1
fi
EOF
Trust… but verify:
beaker@SAL9000:~> sycl-ls
[level_zero:gpu][level_zero:0] Intel(R) oneAPI Unified Runtime over Level-Zero V2, Intel(R) Arc(TM) Pro B60 Graphics 20.1.0 [1.15.39122]
[level_zero:gpu][level_zero:1] Intel(R) oneAPI Unified Runtime over Level-Zero V2, Intel(R) Arc(TM) Pro B60 Graphics 20.1.0 [1.15.39122]
[opencl:cpu][opencl:0] Intel(R) OpenCL, AMD EPYC 7513 32-Core Processor OpenCL 3.0 (Build 0) [2026.21.7.0.24_160000]
beaker@SAL9000:~> icpx --version
Intel(R) oneAPI DPC++/C++ Compiler 2026.1.1 (2026.1.1.20260724)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/intel/oneapi/compiler/2026.1/bin/compiler
Configuration file: /opt/intel/oneapi/compiler/2026.1/bin/compiler/../icpx.cfg
Vulkan
Easy:
beaker@SAL9000:~> sudo zypper --non-interactive install libvulkan1 libvulkan_intel vulkan-tools
Verify:
beaker@SAL9000:~> vulkaninfo --summary
'DISPLAY' environment variable not set... skipping surface info
WARNING: [../src/intel/vulkan/anv_physical_device.c:2836] Code 0 : Unable to open device : No such file or directory (VK_ERROR_INCOMPATIBLE_DRIVER)
==========
VULKANINFO
==========
Vulkan Instance Version: 1.4.357
Instance Extensions: count = 26
-------------------------------
VK_EXT_acquire_drm_display : extension revision 1
VK_EXT_acquire_xlib_display : extension revision 1
VK_EXT_debug_report : extension revision 10
VK_EXT_debug_utils : extension revision 2
VK_EXT_direct_mode_display : extension revision 1
VK_EXT_display_surface_counter : extension revision 1
VK_EXT_headless_surface : extension revision 1
VK_EXT_layer_settings : extension revision 2
VK_EXT_surface_maintenance1 : extension revision 1
VK_EXT_swapchain_colorspace : extension revision 5
VK_KHR_device_group_creation : extension revision 1
VK_KHR_display : extension revision 23
VK_KHR_external_fence_capabilities : extension revision 1
VK_KHR_external_memory_capabilities : extension revision 1
VK_KHR_external_semaphore_capabilities : extension revision 1
VK_KHR_get_display_properties2 : extension revision 1
VK_KHR_get_physical_device_properties2 : extension revision 2
VK_KHR_get_surface_capabilities2 : extension revision 1
VK_KHR_portability_enumeration : extension revision 1
VK_KHR_surface : extension revision 25
VK_KHR_surface_maintenance1 : extension revision 1
VK_KHR_surface_protected_capabilities : extension revision 1
VK_KHR_wayland_surface : extension revision 6
VK_KHR_xcb_surface : extension revision 6
VK_KHR_xlib_surface : extension revision 6
VK_LUNARG_direct_driver_loading : extension revision 1
Instance Layers: count = 1
--------------------------
VK_LAYER_MESA_device_select Linux device selection layer 1.4.303 version 1
Devices:
========
GPU0:
apiVersion = 1.4.354
driverVersion = 26.2.1
vendorID = 0x8086
deviceID = 0xe211
deviceType = PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
deviceName = Intel(R) Arc(tm) Pro B60 Graphics (BMG G21)
driverID = DRIVER_ID_INTEL_OPEN_SOURCE_MESA
driverName = Intel open-source Mesa driver
driverInfo = Mesa 26.2.1
conformanceVersion = 1.4.0.0
deviceUUID = 868011e2-0000-0000-0100-000000000000
driverUUID = beb33ed6-1b6b-4804-f218-acbcea808065
GPU1:
apiVersion = 1.4.354
driverVersion = 26.2.1
vendorID = 0x8086
deviceID = 0xe211
deviceType = PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
deviceName = Intel(R) Arc(tm) Pro B60 Graphics (BMG G21)
driverID = DRIVER_ID_INTEL_OPEN_SOURCE_MESA
driverName = Intel open-source Mesa driver
driverInfo = Mesa 26.2.1
conformanceVersion = 1.4.0.0
deviceUUID = 868011e2-0000-0000-0200-000000000000
driverUUID = beb33ed6-1b6b-4804-f218-acbcea808065
NOTE: Mesa’s Vulkan loader walks every DRM node it finds, including card0 (the software bochs-drm framebuffer on my Proxmox VE hypervisor). That device has no render node and can’t back a Vulkan physical device, so Mesa logs the warning and moves on. It’s noise from the virtual console, not from the passed-through GPUs. Pay no mind.
Unsloth Studio
By default, the installation script for Unsloth Studio checks macOS (eww), then nvidia-smi ($$$), then AMD ROCm (rocminfo/amd-smi) – and that’s it. There is no Intel/XPU probe anywhere in the auto-detect path (the installer’s “gpu: none (CPU-only)” notice is a disgusting lie. Let’s get out the duct tape.
Running the installer with an explicit override resolves to PyTorch’s official XPU index. It’ll also pull in an XPU-enabled bitsandbytes (≥0.50.0, needed for 4-bit QLoRA on Intel) as a separate step gated on the same XPU index detection.
Remember! Before you install or update Unsloth Studio, also define “export UNSLOTH_TORCH_INDEX_FAMILY=xpu” first – otherwise, no XPU.
beaker@SAL9000:~> export UNSLOTH_TORCH_INDEX_FAMILY=xpu
beaker@SAL9000:~> curl -fsSL https://unsloth.ai/install.sh | sh
🦥 Unsloth Studio Installer
────────────────────────────────────────────────────
platform linux
deps using prebuilt llama.cpp (missing: libcurl4-openssl-dev)
Not required to run: Unsloth downloads a prebuilt inference engine.
venv creating Python 3.13 virtual environment
/home/beaker/.unsloth/studio/unsloth_studio
venv using environment
/home/beaker/.unsloth/studio/unsloth_studio
gpu none (CPU-only)
installing PyTorch (https://download.pytorch.org/whl/xpu)...
installing unsloth (this may take a few minutes)...
unsloth 2026.8.22 installed
installing bitsandbytes with Intel XPU kernels...
setup running unsloth studio update...
🦥 Unsloth Studio Setup
────────────────────────────────────────────────────
frontend bundled (pip install)
installing isolated Node (system Node/npm left untouched)...
node v24.18.0 | npm 11.16.0 (isolated)
frontend up to date
deps [==------------------] 2/15 torch check (xpu)
replacing triton 3.8.0 with triton-xpu==3.6.0 (Intel XPU)
deps [======--------------] 5/15 dependency overrides
torch 2.10.0+xpu detected -- installing torchao==0.16.0
deps [=========-----------] 7/15 flash-attn
warning No compatible flash-attn prebuilt wheel found
deps [====================] 15/15 torch final (xpu)
replacing triton 3.8.0 with triton-xpu==3.6.0 (Intel XPU)
deps installed
transformers 5.3.0 pre-installed
transformers 5.5.0 pre-installed
transformers 5.10.2 pre-installed
gpu Intel GPU detected (XPU runtime)
PyTorch XPU (SYCL) provides training and GPU inference on this GPU.
installing prebuilt llama.cpp...
llama.cpp prebuilt installed and validated
installed release: unslothai/llama.cpp@b10715-mix-86bd2d3 (tag b10715)
whisper.cpp prebuilt installed
────────────────────────────────────────────────────
Unsloth Studio Installed
────────────────────────────────────────────────────
launch unsloth studio -p 8888
(add -H 0.0.0.0 for LAN / cloud access; exposes the raw port only, not a public URL)
(add -H 0.0.0.0 --cloudflare for a public Cloudflare HTTPS link, or --secure to keep the raw port private; anyone with the API key can run code)
Created Unsloth Studio shortcut
Unsloth Studio installed!
────────────────────────────────────────────────────
Start Unsloth Studio now? [Y/n]
Oooooh, it worked!
Because we want to access this instance from other workstations, launch it manually with LAN access allowed. What you do from there is your business. Just know I’m scanning the Internet constantly \m/
Go change the world with your new toy:
beaker@SAL9000:~> unsloth studio -p 8888 -H 0.0.0.0
Starting Unsloth Studio on http://WAN.IP:8888
Session log: /home/beaker/.unsloth/studio/logs/server/server-20260902-011057-pid10791.log
{"timestamp": "2026-09-02T05:10:57.957849Z", "level": "info", "event": "run_server startup begin api_only=False host=0.0.0.0 port=8888"}
Loading Unsloth Studio, please wait... (this can take a few minutes)
- loading PyTorch, Unsloth and Transformers...
{"timestamp": "2026-09-02T05:11:01.656084Z", "level": "info", "event": "Imported FastAPI app in 3589.0ms"}
- Starting server...
{"timestamp": "2026-09-02T05:11:01.658754Z", "level": "info", "event": "Ensured Unsloth directories in 3705.6ms"}
[OK] Frontend loaded from /home/beaker/.unsloth/studio/unsloth_studio/lib/python3.13/site-packages/studio/frontend/dist
{"timestamp": "2026-09-02T05:11:01.723571Z", "level": "info", "event": "run_server pre-uvicorn setup completed in 3770.4ms"}
INFO: Started server process [10791]
INFO: Waiting for application startup.
{"timestamp": "2026-09-02T05:11:01.843283Z", "level": "info", "event": "Removing unsloth compiled cache: /home/beaker/.unsloth/studio/compiled_cache"}
{"timestamp": "2026-09-02T05:11:02.021233Z", "level": "info", "event": "lifespan pre-auth setup completed in 179.1ms"}
============================================================
DEFAULT ADMIN ACCOUNT CREATED
username: unsloth
password saved to: /home/beaker/.unsloth/studio/auth/.bootstrap_password
Open the Unsloth UI to sign in and change it.
============================================================
{"timestamp": "2026-09-02T05:11:02.087297Z", "level": "info", "event": "lifespan startup completed in 245.2ms"}
INFO: Application startup complete.
INFO: Unsloth Studio running on http://WAN.IP:8888 (To stop: press Ctrl+C -- on macOS, Control+C not Command+C)
{"timestamp": "2026-09-02T05:11:02.091028Z", "level": "info", "event": "Uvicorn startup hook completed in 4137.9ms"}
{"timestamp": "2026-09-02T05:11:02.091493Z", "level": "info", "event": "run_server uvicorn ready after 4138.3ms"}
{"timestamp": "2026-09-02T05:11:02.673099Z", "level": "info", "event": "Unsloth will shut down in 3600s unless the default admin password is changed."}
🦥 Unsloth Studio is running
────────────────────────────────────────────────────
On this machine -- open this in your browser:
http://127.0.0.1:8888
(same as http://localhost:8888)
From another device on your network / to share:
http://WAN.IP:8888
API & health:
http://127.0.0.1:8888/api
http://127.0.0.1:8888/api/health
────────────────────────────────────────────────────
Hardware detected: XPU — Intel(R) Arc(TM) Pro B60 Graphics
{"timestamp": "2026-09-02T05:11:03.685336Z", "level": "info", "event": "InferenceOrchestrator initialized (subprocess mode)"}
Reachability check: http://WAN.IP:8888/ is NOT reachable from the public internet (3/3 probe nodes failed).
Usually a cloud firewall (AWS security group, GCP firewall / Azure NSG rule) or home router isn't allowing inbound TCP 8888.
No firewall change needed -- SSH local-forward from your own computer:
ssh -L 8888:localhost:8888 <user>@WAN.IP
then open http://localhost:8888/ in your browser.
You can access Unsloth Studio locally in the meantime: http://127.0.0.1:8888
Cloudflare tunnel: OFF (default). Unsloth is reachable on your local network only. Pass --cloudflare to expose a public Cloudflare HTTPS link.
Server-side tools follow each request's enable_tools; the Unsloth UI's tool toggles decide. Pass --enable-tools to force them on for every request.
To stop Unsloth Studio: press Ctrl+C (Control+C, not Command+C, on macOS).
────────────────────────────────────────────────────
{"timestamp": "2026-09-02T05:11:14.105065Z", "level": "info", "event": "torch warm finished in 12018.2ms"}
Note: It will always display your WAN’s IP address, when it really means your host’s IP address. Odd it does’t make that clearer.
SYCL vs Vulkan
Here’s some knowledge for you – because after logging into Unsloth Studio, you probably saw this and thought “WTF? We setup SYCL and only Vulkan is available!”:

Well, two distinct GPU-acceleration paths exist inside Unsloth Studio, and each uses a different backend for Intel.
Training / Fine-Tuning (LoRA, QLoRA, etc.)
Runs through PyTorch, which uses the XPU (SYCL) backend over Level Zero. This is the layer we setup (xe kernel driver → Level Zero → oneAPI-style +xpu PyTorch wheel)
Chat / GGUF Inference
Runs through a bundled llama.cpp prebuilt binary, entirely separate code from PyTorch. install_llama_prebuilt.py has zero references to SYCL anywhere. For any non-NVIDIA/non-AMD GPU, the logic is explicit:log(f"Intel GPU detected -- using upstream Vulkan prebuilt {vulkan_name}")
Unsloth only ships/downloads prebuilt llama.cpp binaries for CUDA, ROCm/HIP, Vulkan, and CPU. There is no SYCL-flavored llama.cpp prebuilt in their release assets, so Intel GPUs always fall through to the Vulkan build for this component — regardless of what PyTorch is doing.
llama.cpp does have an upstream SYCL build target, but Unsloth doesn’t build/ship it as a prebuilt. Vulkan is their catch-all for “any other GPU,” which happens to work fine on Arc/Xe2 hardware since Intel has Vulkan compute support.
Training will use SYCL/XPU via PyTorch, and GGUF chat/inference will use Vulkan via llama.cpp. If you specifically want SYCL-accelerated llama.cpp instead of Vulkan (I’ve found it to be more performant – mostly), that would mean building llama.cpp yourself with -DGGML_SYCL=ON against the oneAPI
toolkit we already installed, replacing Studio’s prebuilt. Pain in the ass, but possible nonetheless.
Intel ECC VRAM Robbery Scheme – Work Around

As I mentioned at the top of this guide, we have a quirk with the VRAM on these cards. In my testing, the B60 went from a spec-sheet “24GB” to Memory Physical Size: 24480.00 MiB usable once I disabled ECC – meaning with ECC on by default, roughly 4GB of that 24GB was gone before I ever loaded a model. Nobody’s published that number that I could find (this hardware is too new), so take it as my measurement, not a documented spec – but a 16.7% cut is a lot, especially compared to Nvidia’s own GDDR6X cards: RTX 4090 owners lose 24GB → 22.5GB (a 6.25% cut) when its on-die ECC-like mode gets switched on (https://dev.to/maximsaplin/4090-ecc-on-vs-ecc-off-36m4). If Intel’s real-world number holds up as more people use these cards, that’s more than double Nvidia’s overhead for the same underlying memory technology. My guess is Intel’s parity/reservation scheme is comparatively wasteful, or they’re reserving more than strict parity bits alone – but that’s speculation on my part.
GDDR6 has no dedicated sideband channel for this. There’s no extra physical bit lane reserved for parity – GDDR6 was designed as a cost-optimized, high-clock commodity memory standard, not a check-bit-aware one (GDDR6 vs HBM (https://www.exxactcorp.com/blog/hpc/gddr6-vs-hbm-gpu-memory)). So any vendor implementing ECC over GDDR6 has to do it the only way available: carve parity storage out of the same visible memory pool the GPU already has. Nvidia eats that cost on the 4090 as shown above; I’d expect AMD’s GDDR6 workstation cards (Radeon Pro W-series) to take a similar hit when ECC is on, though I don’t have a verified number for those to point to, so don’t quote me on AMD specifically. HBM2 (and HBM2E) sidesteps the whole problem with a dedicated sideband ECC path – extra pins/bits alongside the main data bus, purpose-built for parity, instead of stealing from the same pool your models have to live in. That’s one reason I still like my AMD Instinct MI100 and Nvidia Tesla V100 GPUs better, despite being older.
The Fix
Intel’s xpu-smi (from the XPU Manager project) exposes a firmware-level ECC toggle via IGSC (Intel Graphics System Controller): xpu-smi config -d –memoryecc 0. It’s not in Tumbleweed’s repos, and Intel currently only ships .deb builds in their GitHub releases (no RPM despite their docs still describing SLES/RHEL install). The .deb is just one binary + a resources folder, and its only two missing runtime deps (libigsc.so.1, libhwloc.so.15) are both available straight from Tumbleweed’s own OSS repo – everything else it needs (libze_loader, libpciaccess, libstdc++, libz) we already have.
ECC is only really important for activities like training. Inference can be a little more relaxed, that’s why we’re doing this.
Install the two missing runtime libs:
beaker@SAL9000:~> sudo zypper --non-interactive install igsc libhwloc15
Grab and extract the xpu-smi .deb (no RPM exists, so we’ll lift the binary out manually):
beaker@SAL9000:~> curl -fsSL -o /tmp/xpu-smi.deb "https://github.com/intel/xpumanager/releases/download/v2.1.0/xpu-smi_2.1.0%2B26.33.6468cec-1.24.04_amd64.deb"
beaker@SAL9000:~> mkdir -p /tmp/xpu-smi-extract && cd /tmp/xpu-smi-extract
beaker@SAL9000:/tmp/xpu-smi-extract> ar x /tmp/xpu-smi.deb
beaker@SAL9000:/tmp/xpu-smi-extract> zstd -d data.tar.zst -o data.tar
data.tar.zst : 3696640 bytes
beaker@SAL9000:/tmp/xpu-smi-extract> tar xf data.tar
beaker@SAL9000:/tmp/xpu-smi-extract> sudo cp usr/bin/xpu-smi /usr/local/bin/
beaker@SAL9000:/tmp/xpu-smi-extract> sudo mkdir -p /usr/local/share/xpum
beaker@SAL9000:/tmp/xpu-smi-extract> sudo cp -r usr/share/xpum/resources /usr/local/share/xpum/
Note: Installed under
/usr/local, not/usr– it’s an unmanaged file drop, not a zypper tracked package, so keep it out of/usrproper.
Confirm xpu-smi works, and then disable ECC on both GPUs (device IDs from the discovery output -almost certainly 0 and 1):
Note: openSUSE’s default
/etc/sudoerssetssecure_path="/usr/sbin:/usr/bin:/sbin:/bin", which deliberately excludes/usr/local/bin(unlike Debian, which include it by default). Your normal shell’s PATH finds the binary fine, but sudo ignores the PATH entirely and only searches its own hardcodedsecure_path.Quick fix: Just use the full path:
sudo /usr/local/bin/xpu-smi discovery
sudo /usr/local/bin/xpu-smi config -d 0 --memoryecc 0
sudo /usr/local/bin/xpu-smi config -d 1 --memoryecc 0Permanent fix (adds
/usr/local/binto sudo’s search path so baresudo xpu-smi ...works going forward):echo 'Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' | sudo tee /etc/sudoers.d/local-pathsudo chmod 0440 /etc/sudoers.d/local-path
sudo visudo -cvisudo -cchecks syntax across all sudoers files/drop-ins. If it doesn’t report an error, the change is safe and live immediately. A malformed sudoers file can lock out sudo entirely.
beaker@SAL9000:~> sudo xpu-smi discovery
Device ID Device Information
0 Device Name: Intel(R) Arc(TM) Pro B60 Graphics
Device State: normal
Vendor Name: Intel(R) Corporation
SOC UUID: 00000000-0000-0001-0000-0000e2118086
PCI BDF Address: 0000:01:00.0
DRM Device: /dev/dri/card1
Function Type: physical
1 Device Name: Intel(R) Arc(TM) Pro B60 Graphics
Device State: normal
Vendor Name: Intel(R) Corporation
SOC UUID: 00000000-0000-0002-0000-0000e2118086
PCI BDF Address: 0000:02:00.0
DRM Device: /dev/dri/card2
Function Type: physical
beaker@SAL9000:~> sudo xpu-smi config -d 0 --memoryecc 0
Successfully disabled ECC memory setting on GPU 0
Please perform Warm reset of the card for the change to take effect.
beaker@SAL9000:~> sudo xpu-smi config -d 1 --memoryecc 0
Successfully disabled ECC memory setting on GPU 1
Please perform Warm reset of the card for the change to take effect.
If this is a bare metal system, a reboot works in this case. This is a firmware/VBIOS-level setting via IGSC, it won’t take effect live.
However, if you’re like me, and this system is a VM with PCIe passthrough on a Proxmox VE hypervisor, you need to kick the cards hard from the Proxmox host itself (my PVE is named tethys, and the VM is, if you haven’t already guessed, SAL9000).
A host-level sysfs reset (SBR/FLR) is not sufficient. A qm stop/qm start VM-level cycle is also not sufficient. What did work: shutdown -h now on the PVE host followed by powering it back on (a soft ACPI poweroff/poweron cycle). A plain warm reboot of the host was not tested, so it’s unknown whether that alone would suffice.
I used this as an opportunity to finally update my PVE node. Because honestly, how often do we want to shutdown all the VMs and reboot this thing?
Your System is up-to-date
Seems you installed a kernel update - Please consider rebooting
this node to activate the new kernel.
starting shell
root@tethys:~# shutdown -h now
Then verify (confirm the ECC field now reads disabled/0 on both devices) and revel in your success:
beaker@SAL9000:~> sudo xpu-smi config -d 0 | grep -A 2 ECC
Memory ECC:
Current: disabled Pending: disabled
beaker@SAL9000:~> sudo xpu-smi config -d 1 | grep -A 2 ECC
Memory ECC:
Current: disabled Pending: disabled
beaker@SAL9000:~> sudo xpu-smi discovery -d 0
Device ID Device Information
0 Device Type: Discrete GPU
Device Name: Intel(R) Arc(TM) Pro B60 Graphics
Device State: normal
PCI Device ID: 0xe211
Vendor Name: Intel(R) Corporation
SOC UUID: 00000000-0000-0001-0000-0000e2118086
Serial Number: unknown
Part Number: unknown
Core Clock Rate: 2400 MHz
Stepping: A0
SKU Type: Production ES
Driver Version: 17012946
Kernel Version: 7.2.2-1-default
GFX Firmware Name: GFX
GFX Firmware Version: BMG__21.1177
GFX Firmware Status: normal
PCI BDF Address: 0000:01:00.0
PCI Slot: N/A
PCIe Generation: N/A
PCIe Max Link Width: N/A
PCIe Max Bandwidth: N/A
Memory Physical Size: 24480.00 MiB
Max Mem Alloc Size: 23256.00 MiB
ECC State: disabled
Number of Memory Channels: 6
Memory Bus Width: 192
Max Hardware Contexts: 65536
Max Command Queue Priority: 0
Number of EUs: 160
Number of Tiles: 1
Number of Slices: 5
Number of Sub Slices per Slice: 4
Number of Threads per EU: 8
Physical EU SIMD Width: 16
Number of Media Engines: 2
Number of Media Enhancement Engines: 2
beaker@SAL9000:~> sudo xpu-smi discovery -d 1
Device ID Device Information
1 Device Type: Discrete GPU
Device Name: Intel(R) Arc(TM) Pro B60 Graphics
Device State: normal
PCI Device ID: 0xe211
Vendor Name: Intel(R) Corporation
SOC UUID: 00000000-0000-0002-0000-0000e2118086
Serial Number: unknown
Part Number: unknown
Core Clock Rate: 2400 MHz
Stepping: A0
SKU Type: Production ES
Driver Version: 17012946
Kernel Version: 7.2.2-1-default
GFX Firmware Name: GFX
GFX Firmware Version: BMG__21.1177
GFX Firmware Status: normal
PCI BDF Address: 0000:02:00.0
PCI Slot: N/A
PCIe Generation: N/A
PCIe Max Link Width: N/A
PCIe Max Bandwidth: N/A
Memory Physical Size: 24480.00 MiB
Max Mem Alloc Size: 23256.00 MiB
ECC State: disabled
Number of Memory Channels: 6
Memory Bus Width: 192
Max Hardware Contexts: 65536
Max Command Queue Priority: 0
Number of EUs: 160
Number of Tiles: 1
Number of Slices: 5
Number of Sub Slices per Slice: 4
Number of Threads per EU: 8
Physical EU SIMD Width: 16
Number of Media Engines: 2
Number of Media Enhancement Engines: 2

But What About SYCL?
As I mentioned earlier, Unsloth Studio doesn’t ship a version of llama.cpp with SYCL enabled. So we’ll do that manually, and point it to the binary we create.
beaker@SAL9000:~> git clone https://github.com/ggml-org/llama.cpp.git
Cloning into 'llama.cpp'...
remote: Enumerating objects: 121486, done.
remote: Counting objects: 100% (91/91), done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 121486 (delta 42), reused 53 (delta 31), pack-reused 121395 (from 2)
Receiving objects: 100% (121486/121486), 426.53 MiB | 74.14 MiB/s, done.
Resolving deltas: 100% (85737/85737), done.
beaker@SAL9000:~> cd llama.cpp
beaker@SAL9000:~/llama.cpp> cmake -B build -DGGML_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DGGML_SYCL_F16=ON
beaker@SAL9000:~/llama.cpp> cmake --build build --config Release -j -v
beaker@SAL9000:~/llama.cpp> ./build/bin/llama-ls-sycl-device
Found 2 SYCL devices:
| | | | |Max | |Max |Global | |
| | | | |compute|Max work|sub |mem | |
|ID| Device Type| Name|Version|units |group |group|size | Driver version|
|--|-------------------|---------------------------------------|-------|-------|--------|-----|-------|---------------------|
| 0| [level_zero:gpu:0]| Intel Arc Pro B60 Graphics| 20.1| 160| 1024| 32| 25669M| 1.15.39122|
| 1| [level_zero:gpu:1]| Intel Arc Pro B60 Graphics| 20.1| 160| 1024| 32| 25669M| 1.15.39122|
SYCL Optimization Feature:
|ID| Device Type|Reorder|
|--|-------------------|-------|
| 0| [level_zero:gpu:0]| Y|
| 1| [level_zero:gpu:1]| Y|
Now restart Unsloth Studio and navigate to Settings -> System -> GGUF inference engine. In the “Custom llama.cpp folder” box, type in the location of your newly created llama.cpp binary (folder navigation doesn’t work). This is my example:

Now, restart again.
NOTE: If you try loading a model now and get
Failed to load model: llama-server could not start: the system library libsvml.so is missing, it’s not actually missing… it’s an environment problem. Studio launches llama-server by copying its own process environment wholesale, so if whatever terminal/session Studio itself is running in never sourced the oneAPI env (the.bashrcblock from earlier only fires for interactive shells – it won’t help a systemd unit, cron job, or a tmux/screen session that predates that edit), the child process can’t find libsvml.so and friends under/opt/intel/oneapi/compiler/2026.1/lib.Quick check before you launch Studio:
echo $LD_LIBRARY_PATH
If that’s empty, stop Studio, open a fresh terminal (or source~/.bashrc), confirm the path shows up, then relaunch:unsloth studio stop
echo $LD_LIBRARY_PATH
unsloth studio -p 8888 -H 0.0.0.0
Wait, Why Is “Compute Backend” Empty Now?
So you pointed Studio at your shiny hand-rolled SYCL binary, GPUs light up, inference actually runs on the cards, and then you open Settings and the “Compute backend” dropdown is just… nothing. Empty. Not even a CPU option.
Turns out this dropdown was never for us. I went digging through Studio’s backend code (routes/llama.py) and found the whole picker is hardcoded to exactly four values: cpu, cuda, rocm, vulkan. Not a sycl in sight. That’s because this thing isn’t “pick which backend runs my inference” – it’s “pick which of Unsloth’s own prebuilt downloads to install,” and Unsloth doesn’t build a SYCL prebuilt (we covered why earlier – Vulkan’s their catch-all for anything that isn’t Nvidia or AMD).
The instant you set a Custom llama.cpp folder, Studio quietly reclassifies your install as a local_link – their term for “the user pointed me at their own build, I don’t manage this anymore” (llama_cpp_update.py, if you want to go read it yourself). And a local_link install makes the backend-switcher shut itself off on purpose: no options, nothing to switch, because it genuinely has no idea what’s living in your directory and isn’t going to pretend otherwise.
So an empty dropdown here isn’t broken. It’s Studio politely getting out of your way. The only check that actually matters is xpu-smi stats -d 0 lighting up during inference. If that’s happening, you’re done and can ignore the dropdown forever.
Stats
So is it worth it to get SYCL working instead of Vulkan for these GPUs?
Yes. On my system, at least.
Qwen3.8-27B-GGUF UD-Q6_K_XL
- Vulkan averaged 11.2 tok/s
- SYCL averaged 19.4 tok/s
Still slow, but not as painful.
Things I Broke So You Don’t Have To (Landmines & Guardrails)
Everything above gets you a working SYCL build wired into Studio. This section is what I learned keeping it alive afterward – the parts where Studio’s SYCL support runs out of road, and the actual working config on the other side of an evening of crashes.
The Auto-Fit Blind Spot
You’ll notice GPU Layers is locked to Auto in the model load settings (you can’t type a number in). This is the same root cause as the empty Compute Backend dropdown earlier: Studio can only compute an automatic VRAM “fit” for CUDA/ROCm/Vulkan (there’s a dedicated free-memory probe for Vulkan in its code; there’s no SYCL equivalent). Without knowing your GPUs’ free memory, it can’t confirm a fit. So it won’t let you touch manual placement, and instead hands the model to llama.cpp’s own --fit on with no explicit device pin, which decided to run this dense a model entirely on CPU rather than guess.
There’s a separate free-text field for extra/raw arguments in the load settings, independent of the locked GPU Layers control. Whatever you put there gets appended after Studio’s own flags, so it wins (llama.cpp is last-flag-wins). This is what forced GPU offload in my scenario:
-ngl -1 --fit off --device SYCL0,SYCL1
The OOM I Walked Into
Forcing full offload this way removes a safety net you don’t see until it’s gone: Studio’s --fit logic normally keeps some layers on CPU host RAM when a config wouldn’t fit in VRAM (a “tensor spill” fallback). --fit off disables that entirely… it’s all-GPU-or-crash with no graceful degradation.
My first real config – full 262144 context, --parallel 4, --kv-unified (one shared KV cache across all 4 slots), full forced offload – ran fine for a while and then died 14 minutes into generation:
level_zero backend failed with error: 39 (UR_RESULT_ERROR_OUT_OF_DEVICE_MEMORY)
The KV cache had grown past what two 24GB cards could hold alongside the model weights. Retrying with the same settings later died even earlier (during model load this time), allocating the KV cache before generation even started.
Cutting context in half and dropping parallel slots to 1 fixed it for good:
-c 131072 --parallel 1
(no --kv-unified needed once there’s only one slot). That survived a 48K-token prompt and 3600+ generated tokens at a steady 15-16 tok/s, with --spec-type draft-mtp --spec-draft-n-max 3 (MTP speculative decoding) layered on top without issue – worth adding once your base config is already stable, not before, since speculative decoding needs its own slice of VRAM too.
Guardrails for Your Own Tuning
- A clean model load proves nothing. My “fixed” config loaded fine and then OOM’d 14 minutes into real generation. Test with an actually long generation (2000+ tokens) before trusting a config change.
- Watch VRAM headroom while it runs, not just at startup:
sudo xpu-smi stats -d 0
sudo xpu-smi stats -d 1
GPU Memory Used climbing steadily toward the 24GB ceiling as generation continues is your early warning, before it becomes a crash. - Start conservative, then push.
--parallel 1,no --kv-unified, and a context size well under your theoretical max is a safer baseline to tune up from than starting maxed out and cutting back after a crash. I’m the only user, so messing with--parallel>1 is of no benefit anyway (unless we’re discussing rare and unusual usage patterns).
Helpful Links
- openSUSE Tumbleweed
- Intel GPU Driver / Level Zero
- oneAPI / SYCL / DPC++
- Unsloth Studio
- Fine-tuning LLMs on Intel GPUs with Unsloth
- unslothai/unsloth GitHub
- Unsloth Documentation
- PR #4384: –with-llama-cpp-dir / Custom llama.cpp folder (https://github.com/unslothai/unsloth/pull/4384)
- Issue #4379: feature request that led to it (https://github.com/unslothai/unsloth/issues/4379)
- llama.cpp / SYCL backend
- Proxmox / PCIe Passthrough




