Krótka odpowiedź: tak, dwie karty pozwolą Ci uruchomić model, który nie mieści się na jednej — ale nie dlatego, że „zsumujesz VRAM w jedną wielką pulę" (to się nie dzieje). VRAM nie tworzy jednej wspólnej puli, ale model może zostać rozłożony między pamięci kilku GPU. llama.cpp i Ollama dzielą model na warstwy i rozkładają je między karty, więc 2× Tesla P40 24GB dają 48 GB łącznego, fizycznego VRAM rozdzielonego między dwa urządzenia — miejsce na jeden duży model, kosztem komunikacji po PCIe. Jeśli jednak Twój model mieści się na jednej większej karcie, dla workloadu podobnego do naszego testu prawie zawsze lepiej wziąć pojedynczą V100 32GB: mniej wąskich gardeł, prościej, szybciej. Poniżej: jak ten podział działa naprawdę, czym sterować, gdzie są wąskie gardła (PCIe, topologia P2P) i kiedy dwie karty mają sens, a kiedy to niepotrzebna komplikacja.
Piszę to, bo „memory pooling" to najczęstszy mit, jaki słyszę przy wielokartowych zestawach. Ludzie wyobrażają sobie, że dwie karty po 24 GB magicznie stają się jedną 48 GB kartą i model zachowuje się jak na pojedynczym GPU. Rzeczywistość jest bardziej prozaiczna — i dużo bardziej użyteczna, jeśli się ją rozumie. Uczciwie: tak, sprzedajemy te karty, także parami (pełne zastrzeżenie na końcu).
Jak naprawdę działa podział modelu
Duży model językowy to stos warstw. Aktualne llama.cpp steruje podziałem między GPU opcją --split-mode, która przyjmuje m.in. trzy tryby:
--split-mode layer(podział warstw) — warstwy 0–N lądują na GPU 0, warstwy N+1–M na GPU 1 itd. Podczas generowania dane „przechodzą" z karty na kartę, warstwa po warstwie. To tryb domyślny, najprostszy i ten, którym zmierzyliśmy wszystkie liczby w tym tekście.--split-mode row(podział wierszowy) — pojedyncze operacje są cięte „w poprzek" między karty, które liczą je równolegle. Potencjalnie lepiej wykorzystuje obie karty, ale mocniej obciąża komunikację między GPU. U nas próba tego trybu nie ruszyła — szczegóły i pomiary niżej, wraz z uczciwym wyjaśnieniem, czego z tego (i czego nie) można wywnioskować.--split-mode tensor— nowszy, eksperymentalny tensor parallelism o osobnych wymaganiach (m.in. co do Flash Attention/KV). Nie testowaliśmy go w tej kampanii, więc się o nim nie wypowiadam.
Uwaga terminologiczna, bo to częste źródło pomyłek: --split-mode wybiera algorytm (layer/row/tensor), a osobna opcja --tensor-split (-ts) ustala tylko proporcje przydziału modelu do kart (np. -ts 1,1 = po równo). --tensor-split nie włącza „tensor split" — to mimo nazwy wyłącznie waga podziału.
Kluczowe: we wszystkich tych trybach każda karta przechowuje przypisane jej fragmenty modelu we własnej, fizycznie oddzielnej pamięci — a w layer razem z warstwami rozkładany jest też związany z nimi KV cache oraz bufory. Nie ma wspólnej puli, nie ma „48 GB jako jeden obszar". Jest rozłożenie jednego dużego modelu na kilka mniejszych pamięci — i to zupełnie wystarcza, żeby uruchomić model, który na jednej karcie by się nie zmieścił.
Dlatego mówię „48 GB łącznie, rozdzielone między dwa GPU", a nie „48 GB puli": suma pamięci ogranicza rozmiar modelu, który zmieścisz, ale realnie dostępne miejsce na same wagi jest mniejsze — zjadają je KV cache, kontekst i bufory per-device. Ten niuans decyduje o tym, czego się spodziewać po wydajności.
Czym sterujesz — CUDA_VISIBLE_DEVICES, --split-mode i --tensor-split
Dźwignie, które warto znać:
CUDA_VISIBLE_DEVICES— wybierasz, które karty widzi proces.CUDA_VISIBLE_DEVICES=0,1używa dwóch pierwszych;=1odpala tylko na drugiej. Przydatne, gdy chcesz odseparować zadania albo zostawić jedną kartę na coś innego.--split-mode(llama.cpp) — jak dzielić model:layer(domyślnie),row,tensor. To ta opcja decyduje o algorytmie.--tensor-split(-ts) (llama.cpp) — w jakich proporcjach rozłożyć model między karty. Przy dwóch identycznych P40 zwykle po równo (-ts 1,1). Przy kartach o różnym VRAM (np. 24 GB + 16 GB) ustawiasz proporcje ręcznie, żeby nie przepełnić mniejszej. To waga podziału, nie wybór trybu.-ngl/ offload warstw — ile warstw w ogóle idzie na GPU (99 = wszystkie). Reszta ląduje na CPU, co dramatycznie spowalnia — celuj w pełny offload na GPU.
W Ollama część tego dzieje się automatycznie, ale gdy chcesz kontroli nad podziałem, llama.cpp daje Ci ją wprost.
Wąskie gardła — PCIe, topologia i NVLink
Skoro dane wędrują między kartami, łącze między nimi staje się wąskim gardłem. I tu jest różnica, którą trzeba znać przed zakupem:
- P40 komunikuje się przez PCIe. Nie ma NVLink. Przy podziale warstw to zwykle akceptowalne (transfer między warstwami jest umiarkowany), ale przy trybach równoległych i większym obciążeniu PCIe potrafi ograniczać. Zadbaj o realne linie PCIe dla każdej karty — nie x1 z taniego risera.
- V100 w wersji SXM2 ma NVLink — bardzo szybkie bezpośrednie łącze między GPU. Ale Tesla V100-PCIE-16GB/32GB używane w naszym teście (ta wersja, którą wkładasz do zwykłej płyty) z NVLink nie korzystają — komunikują się po PCIe jak P40. Nie kupuj SXM2 „bo NVLink", jeśli nie masz serwera SXM2; to karta bezużyteczna bez odpowiedniej płyty nośnej.
Nie zgaduj z liczby linii — zmierz topologię. Zanim uznasz PCIe za wąskie gardło, sprawdź realną generację i szerokość linku oraz fizyczną/logiczną ścieżkę między kartami:
nvidia-smi topo -m
Macierz pokaże, czy para GPU łączy się przez NVLink (NV#), pojedynczy mostek PCIe na tym samym root complexie (PIX/PXB), czy dopiero przez CPU (SYS) — a to, nie sama etykieta „x8 vs x16", decyduje o realnym koszcie komunikacji. Uwaga: PIX/PXB opisują topologię, nie są gwarancją, że CUDA peer access (P2P) faktycznie działa — jeśli interesuje Cię realna możliwość P2P, sprawdź ją osobno odpowiednim testem CUDA/P2P dla swojej platformy. Aktualną szerokość i prędkość linku podejrzysz przez nvidia-smi -q | grep -A2 "Link Width".
Wniosek praktyczny: przy dwóch kartach PCIe (2× P40, 2× V100 PCIe) nie licz na przyspieszenie proporcjonalne do liczby kart. Zyskujesz pojemność (większy model), a nie liniowy wzrost prędkości. Czasem dwie karty są nawet minimalnie wolniejsze na małym modelu niż jedna — bo doszedł narzut komunikacji.
Identyczne czy różne karty — i co z mieszaniem
Najprościej pracuje się na dwóch identycznych kartach (2× P40 albo 2× V100 tej samej wersji): równy podział, przewidywalne zachowanie, żadnych niespodzianek z proporcjami. Wtedy --tensor-split zwykle zostawiasz po równo i temat się kończy.
Mieszanie kart jest możliwe, ale wymaga uwagi. llama.cpp poradzi sobie z kartami o różnym VRAM, o ile ręcznie ustawisz proporcje splitu tak, żeby nie przepełnić mniejszej. Gorzej z mieszaniem architektur — łączenie np. Pascala z Amperem bywa źródłem dziwnych zachowań (różne ścieżki obliczeniowe, różne optymalne kwantyzacje). Przy podziale warstw efekt zależy od proporcji przydziału, charakterystyki każdej karty i komunikacji — wolniejsza karta może stać się wąskim gardłem, jeśli dostanie zbyt dużą część pracy, ale nie zawsze prosto ustala globalny limit. Jeśli budujesz zestaw od zera, trzymaj się jednej generacji i najlepiej identycznych kart — mniej zmiennych, mniej wieczorów na debugowanie.
I jeszcze jedno o skalowaniu: przejście z jednej karty na dwie to skok pojemności, ale każda kolejna karta dokłada narzut komunikacji. Trzy i cztery karty mają sens dopiero przy naprawdę dużych modelach — inaczej dokładasz złożoność (zasilanie, chłodzenie, PCIe, POST — o problemach z POST-em wielokartowych rigów piszemy osobno) bez proporcjonalnego zysku.
Zasilanie i chłodzenie — nie pomiń tego
Dwie karty to do ok. 250 W limitu mocy na kartę plus krótkotrwałe skoki poboru mocy (transienty) przy nagłym obciążeniu. Nie zakładaj z góry stałego 500 W bez pomiaru — to górny limit, nie ciągły pobór. To znaczy:
- Mocny, dobry zasilacz z zapasem i solidną linią 12 V — nie „akurat tyle, ile suma TDP". Transienty potrafią wywalić słaby zasilacz mimo pozornie wystarczającej mocy nominalnej.
- Właściwy przewód/adaptacja zasilania do każdej karty. Użyj kabla zgodnego z wymaganym pinoutem konkretnej karty i platformy — nie zakładaj zgodności tylko dlatego, że złącze mechanicznie przypomina EPS albo PCIe. Podłączenie kabla o złym pinoucie potrafi uszkodzić kartę. (O tej pułapce piszemy osobno.)
- Chłodzenie. To pasywne karty; dwie obok siebie w desktopie potrafią się nawzajem podgrzewać i zdławić. Bez wymuszonego przepływu powietrza wielokartowy zestaw długo nie pociągnie. Jak to zrobić rozsądnie, opisałem w poradniku o chłodzeniu pasywnych kart serwerowych.
Kiedy 2× P40, a kiedy jedna V100 32GB
To jest realna decyzja zakupowa, więc rozłóżmy ją wprost.
| Kryterium | 2× P40 (48 GB łącznie, rozdzielone) | 1× V100 32GB |
|---|---|---|
| Maks. rozmiar modelu | największy (dwie pamięci razem) | do ~32 GB |
| Prędkość na modelu mieszczącym się w 32 GB | niższa (narzut PCIe) | wyższa, prościej |
| Łącze między GPU | PCIe (brak NVLink) | nie dotyczy (jedna karta) |
| Tensor Cores / FP16 | brak (Pascal) | są (Volta) |
| Złożoność konfiguracji | większa (split, tuning) | minimalna |
| Zasilanie/chłodzenie | 2× 250 W, trudniej | jedna karta, łatwiej |
| Kiedy wybrać | model nie mieści się na jednej karcie | model mieści się na jednej karcie |
- Bierz 2× P40, gdy naprawdę potrzebujesz dużego modelu, który nie wejdzie w 24/32 GB jednej karty — i akceptujesz narzut PCIe oraz więcej strojenia. To najtańszy sposób na „dużo VRAM łącznie pod jeden model".
- Bierz jedną V100 32GB, gdy Twój model mieści się w 32 GB — dostajesz Tensor Cores, HBM2, brak narzutu międzykartowego i dużo prostszy setup. Dla większości domowych i firmowych zastosowań to spokojniejszy wybór.
Nasze pomiary (GGUF Q4_K_M, llama-bench build 6ad4ab0, driver 580.173.02, --split-mode layer, -ngl 99, -r 3, pełny power limit 250 W, karty na PCIe Gen3 bez NVLink):
| Konfiguracja | Model | Prompt eval (pp512) | Generacja (tg128) | Uwaga |
|---|---|---|---|---|
| 1× P40 | Qwen2.5-32B Q4 | 225,3 | 10,1 | punkt odniesienia |
| 2× P40 layer | Qwen2.5-32B Q4 | 224,5 | 10,1 | ≈ 1 karta — zysk to pojemność, nie prędkość |
| 2× P40 layer | Llama-3.3-70B Q4 | 101,3 | 4,8 | 70B mieści się dopiero na 2 kartach (~20 GB/kartę) |
| 1× V100-32 | Qwen2.5-32B Q4 | 643,4 | 30,3 | punkt odniesienia |
| 2× V100 layer | Qwen2.5-32B Q4 | 630,2 | 30,7 | ≈ 1 karta |
| 2× V100 layer | Llama-3.3-70B Q4 | 317,3 | 16,0 | ~3× szybciej niż 2× P40 w tym teście |
To dokładnie potwierdza wąską, dobrze udokumentowaną tezę: w tym backendzie, dla tych modeli i quantów, --split-mode layer skaluje pojemność, nie prędkość — gdy model mieścił się na jednej karcie, druga nie zwiększyła throughputu. Nie przenoszę tego na „layer split zawsze skaluje tylko pojemność": przy innym backendzie, batchingu/concurrency czy modelu zachowanie może być inne. Sens dwóch kart to odpalenie modelu, który na jedną nie wchodzi (jak 70B).
Różnica ~3× między 2× V100 a 2× P40 (317,3 vs 101,3 pp512 na 70B) jest zgodna z przewagami architektury Volty — Tensor Cores, HBM2, nowsze kernele — ale nasz benchmark nie izoluje wpływu samych Tensor Cores od pozostałych różnic. Traktuj tę liczbę jako różnicę między dwiema konfiguracjami, nie jako dowód, że „to Tensor Cores dają 3×".
Co z --split-mode row: w naszym buildzie llama.cpp (6ad4ab0) i na tej konkretnej topologii — 2× P40 oraz 2× V100 PCIe — próba --split-mode row zakończyła się błędem ładowania modelu (device does not support split buffers). Działającym i użytym do benchmarku trybem był layer. Nie traktujemy tego jako uniwersalnego ograniczenia wszystkich konfiguracji PCIe — to wynik dla naszego backendu, buildu i topologii, nie dowód, że row/tensor split „z definicji wymaga NVLink". Jeśli zależy Ci na trybach równoległych, sprawdź je na swojej wersji llama.cpp i swojej topologii (nvidia-smi topo -m), bo macierz wsparcia i wymagania — zwłaszcza dla eksperymentalnego --split-mode tensor — zmieniają się między commitami. Twoje liczby będą zależeć od modelu, kwantyzacji, PCIe i długości kontekstu.
Źródła
- llama.cpp — opcje
--split-mode {none,layer,row,tensor}i--tensor-split:llama-cli --help/llama-bench --helpdla użytego commitu (build6ad4ab0); repozytorium: https://github.com/ggml-org/llama.cpp - NVIDIA Tesla V100 — dane techniczne (32 GB HBM2, warianty PCIe/SXM2, NVLink): https://images.nvidia.com/content/technologies/volta/pdf/tesla-volta-v100-datasheet-letter-fnl-web.pdf
Zastrzeżenie na koniec, tak jak zawsze: tak, sprzedajemy te karty, również w parach — więc czytaj to z tą świadomością. Ale nie chcę Ci wcisnąć dwóch kart, jeśli jedna V100 32GB załatwia sprawę prościej i szybciej — to uczciwie tańsze w utrzymaniu i mniej kłopotliwe. Każdą sztukę przepuszczamy przez wieloetapową kwalifikację (odcisk techniczny, kontrola VRAM, burn-in z watchdogiem, ECC, PCIe, kontrola poprawności obliczeń) i dokładamy raport/certyfikat z tego procesu, a przy zestawach dwukartowych pomożemy dobrać zasilanie i ustawienia. Zastanawiasz się, czy Twój model wymaga dwóch kart, czy zmieści się na jednej? Napisz do nas z nazwą modelu i kwantyzacją — policzymy VRAM i doradzimy konfigurację.
(Zobacz też: Chłodzenie pasywnych kart serwerowych)
FAQ
- Czy dwie karty 24 GB dają jedną pulę 48 GB?
- Nie. Nie ma memory poolingu. Model jest dzielony na warstwy między karty; każda trzyma swój kawałek. Suma pamięci ogranicza rozmiar modelu, ale nie działa jak jeden ciągły obszar.
- To po co w ogóle dwie karty, skoro nie sumują się „magicznie"?
- Żeby uruchomić model, który nie mieści się na jednej. Zyskujesz pojemność, nie liniową prędkość. Do dużych modeli to jedyny tani sposób bez kupowania jednej ogromnej karty.
- Czy 2× P40 będą dwa razy szybsze niż jedna?
- Nie. Przy podziale dochodzi narzut komunikacji po PCIe. Na modelu mieszczącym się na jednej karcie dwie potrafią być nawet minimalnie wolniejsze. Skalują pojemność, nie przepustowość.
- P40 ma NVLink?
- Nie. P40 komunikuje się tylko po PCIe. NVLink ma V100 w wersji SXM2 — ale nie V100 PCIe. Nie kupuj SXM2, jeśli nie masz serwera SXM2.
- Jak wybrać, które GPU liczy i jak podzielić model?
CUDA_VISIBLE_DEVICESdecyduje, które karty widać;--split-mode(layer/row/tensor) wybiera algorytm podziału;--tensor-split(-ts) ustala tylko proporcje przydziału (np.-ts 1,1). Przy kartach o różnym VRAM ustaw proporcje ręcznie, by nie przepełnić mniejszej.- Jaki zasilacz do dwóch kart?
- Z realnym zapasem ponad 2× 250 W limitu, dobrą linią 12 V i odpornością na transienty. Każdą kartę zasilaj przewodem o pinoucie zgodnym z tą konkretną kartą i platformą — nie dobieraj kabla po samym kształcie złącza.
