Giriş:
Eski masaüstü bilgisayarımı sanallaştırma vb. deneyler için kullanıyorum. Bir nevi aklıma gelen şeyleri yapabileceğim bir çukur gibi, attığınız yükleri kabul edip iyi-kötü bir şekilde çalıştırıyor. Bu makine bir arkadaşım köşede yatan CPUsunu vermesi ile ile 8 çekirdek 16 threadden, 16 çekirdek 32 threade çıktı, 64GB DDR4 Ram mevcut ve birkaç NVME takılı, üzerinde muhtelif bluetoothlar falan mevcut... Ayrıca bunlara ek olarak üzerinde bir Nvdia 1080TI ve bir de Intel A770 var, tam bir frankenstein. Üzerindeki PCI popülasyonu yoğunluğundan dolayı bu GPUlar da çok verimli çalışıyor diyemeyiz ama istediklerimizi yapacak kadar çalışıyorlar. Bu makinenin üzerine birçok VM attım bunlardan 3ü OpenStack için kullanılıyor. 1 adet controller 2 adet compute şeklinde. Storage tarafında da bir NFS VM mevcut, bunu da o veya bu şekilde OpenStack'e bağladım. Söz konusu gpuları OpenStack'e paslamaya gelince herşey iç-içe. Yani A770 bir VM e paslanıyor, oradan OpenStack kendi oluşturduğu VMe paslıyor... Ana sunucu üzerinde biraz IOMMU kavgası, el ile virsh xml editleyince çalışıyor. Yeterince dövünce çalışıyor da diyebiliriz. İşte öyle bir hikaye.
Malum 1080TI 11GB vram ile A770 de 16GB vram ile geliyor (8GBleri de mevcut herhalde). Bir taraf CUDA koşarken bir taraf oneapi, sycl vs. koşabiliyor. Aslında totalde 27GB vram mevcut, fakat bunları "total" olarak kullanmak mümkünmü onu denemek istedim, maksat performans değil maksat muhabbet.
Öncelikle gpuların pci link hızlarını vereyim, beklentiyi biraz aşağıya çekelim.
root@virtbase:~# lspci | grep -i vga
0c:00.0 VGA compatible controller: Intel Corporation DG2 [Arc A770] (rev 08)
0e:00.0 VGA compatible controller: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] (rev a1)
root@virtbase:~# lspci -vv -s 0c:00.0 | grep -E "LnkCap:|LnkSta:"
LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s <64ns, L1 <1us
LnkSta: Speed 2.5GT/s, Width x1
root@virtbase:~# lspci -vv -s 0e:00.0 | grep -E "LnkCap:|LnkSta:"
LnkCap: Port #2, Speed 8GT/s, Width x16, ASPM L0s L1, Exit Latency L0s <512ns, L1 <4us
LnkSta: Speed 2.5GT/s (downgraded), Width x4 (downgraded)
Amacım bir llama.cpp ile RPC sunucu kaldırmak, bu sunucunun 1080TI ve A770 e bir modeli paylaştırmasını sağlamak (Bakınız: Tensor parallelism, Pipeline parallelism). Bunun için de ana sunucuya ek olarak yine llama.cpp üzerinden CUDA koşan 1080TI ile çalışan bir RPC sunucu, SYCL koşan A770 ile çalışan bir RPC sunucu kaldıracağız. Ana sunucu da bunlara gerekli dağıtımı sağlayacak.
Fikir güzel, işlermi belki. İsimler, jargonlar havada uçuşur. Llm-Hetero, Rpc-Hibrit Llm Inference... Ya tutarsa diyip girişiyoruz.
Gelişme:
Altapım OpenStack Gazpacho, bunun üzerinde Vexxhost Magnum Cluster Api driveri ile OpenStack Magnum koşuyorum, tabi ek olarak Octavia falan da mevcut. Bu Magnum ile de kendi oluşturduğum imajlar üzerinden kubernetes kümeleri kaldırıyorum. Kubernetes versiyon 1.36.2.
Kubernetes kümemizde durum şöyle, 1 master, 1 1080TI worker ve 1 A770 worker.
erdem@EWUL13:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-ngar4-jn72v-c4c7h Ready control-plane,master 20h v1.36.2
kube-ngar4-worker-gpu-1080ti-mnvpd-hhh6v-6klk6 Ready worker 20h v1.36.2
kube-ngar4-worker-gpu-a770-mrzqm-6r6xc-h5wl9 Ready worker 20h v1.36.2
Worker düğümlerimizde gerekli sürücüler tarafımca host seviyesinde yüklendi, 1080TI terk edilmiş bir kart olduğu için Nvidia Sürücüsü versiyonu 580, Cuda versiyonu ise 12.9.2. A770 de ise durum biraz farklı, gerekli sürücü aslında kernel içerisinde bile mevcut (Herhalde 6+ sonrası, i915 ve Xe gömülü geliyor, HWE kernel ile de karıştırıyor olabilirim). Fakat benim gibi kendi düğüm imajlarınızı kendiniz oluşturuyor ve boyuttan tasarruf etmek için herşeyi buduyorsanız dikkat edin. A770 sürücüleri yüklü olmasına rağmen gerekli firmwareleri el ile kopyalamanız gerekebilir sonra initramfs güncellemesi falan...
sudo wget -P /lib/firmware/i915 "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/i915/dg2_guc_70.bin"
sudo wget -P /lib/firmware/i915 "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/i915/dg2_dmc_ver2_08.bin"
Neyse lafı uzatmadan Dockerfile ve RPC sunucularını paylaşalım.
Cuda için Dockerfile:
# ---- build
FROM nvidia/cuda:12.9.2-devel-ubuntu24.04 AS build
RUN apt-get update && apt-get install -y --no-install-recommends git build-essential cmake ninja-build && rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN git clone --depth 1 https://github.com/ggml-org/llama.cpp.git .
RUN cmake -B build -G Ninja -DGGML_CUDA=ON -DGGML_RPC=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS=-Wl,--allow-shlib-undefined && cmake --build build --target ggml-rpc-server -j"$(nproc)"
RUN ldd build/bin/ggml-rpc-server
# ---- runtime
FROM nvidia/cuda:12.9.2-runtime-ubuntu24.04
RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 && rm -rf /var/lib/apt/lists/*
COPY --from=build /build/build/bin/ggml-rpc-server /usr/local/bin/ggml-rpc-server
COPY --from=build /build/build/bin/*.so* /usr/local/lib/
RUN ldconfig
ENTRYPOINT ["/usr/local/bin/ggml-rpc-server"]
CMD ["-H", "0.0.0.0", "-p", "50052"]
SYCL için Dockerfile (Runtime imajında çalıştıramadım, çok uğraşamadım 4.4GB lık bir canavar çıktı)
# ---- build
FROM intel/oneapi-basekit:2025.3.2-0-devel-ubuntu24.04 AS build
RUN apt-get update && apt-get install -y --no-install-recommends git cmake ninja-build && rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN git clone --depth 1 https://github.com/ggml-org/llama.cpp.git .
#SHELL ["/bin/bash", "-c"]
RUN source /opt/intel/oneapi/setvars.sh --force && cmake -B build -G Ninja -DGGML_SYCL=ON -DGGML_RPC=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DCMAKE_BUILD_TYPE=Release && cmake --build build --target ggml-rpc-server -j"$(nproc)"
RUN ldd build/bin/ggml-rpc-server
# ---- runtime
FROM intel/oneapi-basekit:2025.3.2-0-devel-ubuntu24.04
RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 && rm -rf /var/lib/apt/lists/*
COPY --from=build /build/build/bin/ggml-rpc-server /usr/local/bin/ggml-rpc-server
COPY --from=build /build/build/bin/*.so* /usr/local/lib/
RUN ldconfig
COPY entrypoint-sycl.sh /usr/local/bin/entrypoint-sycl.sh
RUN chmod +x /usr/local/bin/entrypoint-sycl.sh
ENTRYPOINT ["/usr/local/bin/entrypoint-sycl.sh"]
CMD ["-H", "0.0.0.0", "-p", "50052"]
A770 için entrypoint (ZES_ENABLE_SYSMAN i nerede sağlarsam sağlayım loga döktüğü warningi aşamadım. xpu-smi ile de GPU Util değerini sorunsuz ve düzgün bir şekilde alamadım)
export ZES_ENABLE_SYSMAN=1
source /opt/intel/oneapi/setvars.sh --force
exec /usr/local/bin/ggml-rpc-server "$@"
Ana sunucu için RPC Dockerfile
FROM ubuntu:24.04 AS build
RUN apt-get update && apt install -y --reinstall ca-certificates && update-ca-certificates && apt-get install -y --no-install-recommends git build-essential cmake ninja-build && rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN git clone --depth 1 https://github.com/ggml-org/llama.cpp.git .
RUN cmake -B build -G Ninja -DGGML_RPC=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build --target llama-server -j"$(nproc)"
# ---- runtime image ----
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 ca-certificates curl && rm -rf /var/lib/apt/lists/*
COPY --from=build /build/build/bin/llama-server /usr/local/bin/llama-server
COPY --from=build /build/build/bin/*.so* /usr/local/lib/
RUN ldconfig
ENTRYPOINT ["/usr/local/bin/llama-server"]
Bunları paketleyince sadece ayağa kaldırmak kalıyor. Bunları biraz kısaltarak paylaşayım yazı fazla uzamasın.
CUDA:
...
containers:
- name: rpc-server
image: kendi-repo-adresin/rpc:cuda
args: ["-H", "0.0.0.0", "-p", "50052"]
ports:
- containerPort: 50052
name: rpc
resources:
limits:
nvidia.com/gpu: 1
...
requests:
nvidia.com/gpu: 1
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-cuda
namespace: llm-hetero
labels:
app: rpc-cuda
spec:
clusterIP: None # headless — single pod, stable DNS: rpc-cuda.llm-hetero.svc.cluster.local
selector:
app: rpc-cuda
ports:
- port: 50052
targetPort: 50052
name: rpc
SYCL: (GGML_SYCL_ENABLE_OPT için kesinlikle şu linke bakın )
...
containers:
- name: rpc-server
image: kendi-repo-adresin/rpc:sycl
args: ["-H", "0.0.0.0", "-p", "50052"]
env:
- name: GGML_SYCL_ENABLE_OPT
value: "0"
...
ports:
- containerPort: 50052
name: rpc
resources:
limits:
gpu.intel.com/i915: 1
...
requests:
gpu.intel.com/i915: 1
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-sycl
namespace: llm-hetero
labels:
app: rpc-sycl
spec:
clusterIP: None # headless — single pod, stable DNS: rpc-sycl.llm-hetero.svc.cluster.local
selector:
app: rpc-sycl
ports:
- port: 50052
targetPort: 50052
name: rpc
ANA: (Ana Sunucuda modeli kendi lokal ağım üzerinden indiriyorum, persisten volume e yazılıyor) Ek olarak load-balancer kısmımız var ki OpenStack tarafında loadbalancer oluşsun ve biz arayüze düşebilelim.
...
initContainers:
- name: fetch-model
image: curlimages/curl:8.9.1
envFrom:
- configMapRef:
name: model-source
command:
- sh
- -c
- |
if [ ! -f /models/model2.gguf ]; then
echo "Downloading $MODEL_URL"
curl -fL --retry 3 --retry-delay 5 "$MODEL_URL" -o /models/model2.gguf.tmp
mv /models/model2.gguf.tmp /models/model2.gguf
else
echo "Model already cached"
fi
volumeMounts:
- name: model-storage
mountPath: /models
containers:
- name: llama-server
image: kendi-repo-adresin/rpc:main
args:
- "-m"
- "/models/model2.gguf"
- "--host"
- "0.0.0.0"
- "--port"
- "8080"
- "-ngl"
- "99"
- "--rpc"
- "rpc-sycl.llm-hetero.svc.cluster.local:50052,rpc-cuda.llm-hetero.svc.cluster.local:50052"
- "-c"
- "131072"
ports:
- containerPort: 8080
name: http
---
apiVersion: v1
kind: Service
metadata:
name: main-server
namespace: llm-hetero
labels:
app: main-server
spec:
type: LoadBalancer
selector:
app: main-server
ports:
- port: 8080
targetPort: 8080
name: http
Bunlarla beraber yeterince bekleyerek podlar yerine oturuyor.
Sonuç:
Gelelim sonuca, Qwen3.6-35B-A3B-Q4_K_M.gguf modeli için 131072 context size ile bütün layerları gpulara atabiliyoruz. Başlangıç olarak 1080TI tarafında 9700 MB, A770 tarafında 13600 MB vram kullanımı mevcut. Total 27 GB vram üzerinden 22.75GB mertebesine ulaştık sadece başlangıç ile diyeibliriz.
1080TI Nvidia-Smi:
...
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
| 0 NVIDIA GeForce GTX 1080 Ti On | 00000000:00:05.0 Off | N/A |
| 0% 38C P8 14W / 320W | 9751MiB / 11264MiB | 0% Default |
| | | N/A |
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
| 0 N/A N/A 9813 C /usr/local/bin/ggml-rpc-server 9746MiB |
A770 xpu-smi:
root@kube-ngar4-worker-gpu-a770-mrzqm-6r6xc-h5wl9:~# xpu-smi dump --metrics 1,18 --interval 2
DeviceId power.draw (W) memory.used (MiB)
0 36.18 13662.97265625
Peki bunca emeğe karşın gerekli token saniyeyi üretebildik mi. Tabi ki hayır. A770 gpu utilizasyonunda verdiği değerler doğru ise %40 ş geçemedi hiçbir zaman, 1080TI ise %12 utilizasyona kadar nadir yükseldi. Yani sadece layerları gpu yükleyebilmiş oldu, GPU nun kendi faydasını göremedik bile. Bakınız aşağıda sonuçları veriyorum.
7.49.302.746 I srv load_model: initializing, n_slots = 4, n_ctx_slot = 131072, kv_unified = 'true'
7.49.352.225 I srv init: chat template supports preserving reasoning, consider enabling it via --reasoning-preserve
7.49.352.287 I srv llama_server: model loaded
7.49.352.292 I srv llama_server: listening on http://0.0.0.0:8080
87.11.318.373 I slot get_availabl: id 3 | task -1 | selected slot by LRU, t_last = -1
87.11.318.534 I slot launch_slot_: id 3 | task 0 | processing task, is_child = 0
87.26.895.011 I slot print_timing: id 3 | task 0 | n_decoded = 100, tg = 8.41 t/s, tg_3s = 8.41 t/s
87.29.986.842 I slot print_timing: id 3 | task 0 | n_decoded = 124, tg = 8.28 t/s, tg_3s = 7.76 t/s
87.33.035.898 I slot print_timing: id 3 | task 0 | n_decoded = 150, tg = 8.32 t/s, tg_3s = 8.53 t/s
87.36.063.507 I slot print_timing: id 3 | task 0 | n_decoded = 174, tg = 8.26 t/s, tg_3s = 7.93 t/s
87.39.228.127 I slot print_timing: id 3 | task 0 | n_decoded = 191, tg = 7.89 t/s, tg_3s = 5.37 t/s
87.42.282.798 I slot print_timing: id 3 | task 0 | n_decoded = 207, tg = 7.59 t/s, tg_3s = 5.24 t/s
87.45.392.313 I slot print_timing: id 3 | task 0 | n_decoded = 225, tg = 7.40 t/s, tg_3s = 5.79 t/s
87.48.422.879 I slot print_timing: id 3 | task 0 | n_decoded = 246, tg = 7.36 t/s, tg_3s = 6.93 t/s
Aynı modeli laptopta 4080mobil ile sadece 10 layer GPU üzerinde olacak şekilde denediğimde ise 18 token saniye gibi değerler görebildim. Peki bunu niye denedin o zaman dersiniz, amacım öncelikle çalışacak mı onu görmekti, sonrasında ise gerçekten bir modeli dağıtarak anca çalışabilir hale getireceksek RPC buna yarayacak mı onu anlamaktı. RPC ile bu yapılabiliyor, böylelikle birçok GPU bulunduran sunucuyu birbirine bağlayarak TCP üzerinden bu modelleri o veya bu şekilde çalışabilir hale getirebiliriz, bunu görmüş yolduk. Yani amacıma ulaşabildim mi evet. Bu token hızı ile reasonin yapan modelin sonucunu beklermiyiz, bence hayır.
Referanslar:
Teşekkür:
Ana fotoğraf: Frames For Your Heart orijinaline Unsplash üzerinden ulaşabilirsiniz.
