Автор: Александр Казанцев, руководитель направления по работе с документацией и контентом HOSTKEY
При сборке GPU-серверов или при проблемах с ними, которые сообщают наши клиенты, нам необходимо проводить их тестирование. Так как разворачивание LLM-моделей в Ollama является одним из сценариев их использования и мы предлагаем готовые панели с моделями на её основе, то нам необходимо также проверять машины на работоспособность и под нагрузкой в инференсе через нее и иметь результаты для сравнения.
|
GPU-серверы — почасовая тарификация Мощные серверы с видеокартами NVIDIA последних поколений. Почасовая и помесячная оплата со скидкой. |
Поискав среди open-source решений, мы не нашли готового бенчмарка, поэтому решили написать свой тест. Алгоритм тестирования было решено сделать следующий (изначально):
Ставим в систему Ollama. Драйвера видеокарты и CUDA должны быть установлены ранее.
Определяем доступный объем видеопамяти и в зависимости от него ставим модель нужного размера. Из подходящих моделей оптимальным оказался DeepSeek с 14/32/70 миллиардами параметров и максимальным размером контекста в 128K. Тестировать будем GPU с размером видеопамяти от 16 Гб и выше.
Запускаем генерацию одного и того же промта (оптимально генерация кода, чтобы получить объем ответа) на данной модели, постепенно увеличивая контекст (ctx) с 2000 до максимального для модели с шагом в 2000 токенов.
Записываем полученные характеристики (время генерации, число токенов в секунду и другие) из Ollama и параметры нагрузки видеокарт из nvidia-smi.
Определяем зависимость параметров от модели и ctx и находим эталонные показатели для последующего сравнения.
Первый вариант
Скрипт решили сделать на bash, чтобы не заморачиваться с Python или другими языками. Из дополнительных пакетов нужен будет только jq для работы с JSON-ответами от Ollama и curl, который стоит по дефолту в используемых нами Ubuntu 22.04 (и 24.04).
Размер видеопамяти определим через ollama serve и обработку ее вывода. Нюанс тут в том, что по дефолту Ollama ставится как сервис и при попытке запустить данную команду Ollama будет ругаться на уже запущенный инстанс. Значит, нам надо:
а) остановить сервис Ollama;
б) запустить команду ollama serve;
в) из вывода вытащить все строки с доступной памятью и поместить значение в массив типа [0]="15.8", [1]="15.8":
grep -o 'available="[^"]*"' | grep -o '[0-9.]*'
г) обработать вывод через регулярное выражение и, сложив цифры, так как у нас есть конфигурации с 2 или 4 GPU, получить суммарный объем:
printf '%s GiB\n' "${available_memory[@]}"
total_available=$(echo "$log_output" | awk -F'available="' '/available="/ { gsub(/".*/, "", $2); sum += $2 } END { print sum+0 }')
Да, можно было получить цифры через команду:
nvidia-smi --query-gpu=memory.free
Но через ollama serve сразу же можно определить, что GPU не видится, так как тогда вместо видеопамяти выдаст размер доступного ОЗУ сервера.
После запустить заново systemd сервис Ollama. Всю дальнейшее взаимодействие с ней будем делать через API.
Затем, исходя из объема суммарной видеопамяти, нужно выбрать нужную модель по таким параметрам:
Deepseek-r1:14b = 15 ГиБ (Числа получаем именно в гибибайтах, а не в гигабайтах.)
Deepseek-r1:32b = 23 ГиБ
Deepseek-r1:70b" = 48 ГиБ
«Прогреть» модель, запустив Ollama с ней. Это нужно, чтобы в результатах бенчмарка цифры были без потерь времени на загрузку модели в память:
curl -s http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d '{"model":"'"$MODEL"'","prompt":"Hello","stream":false}' \
>/dev/null
После этого можно запустить цикл, в котором мы увеличиваем контекст (параметр ctx) с 2000 до 128000 и просим нейросеть сгенерировать нам игру промтом «Generate Tetris game on HTML and JS»:
curl -s --max-time 300 \
-H "Content-Type: application/json" \
-d '{
"model": "'"$MODEL"'",
"prompt": "'"$prompt"'",
"stream": false,
"options": {
"num_ctx": '"$num_ctx"'
}
}' \
http://localhost:11434/api/generate > "$response_file"
Ответ получаем, сохраняем его на всякий случай для изучения в файл и вытаскиваем из него нужные нам параметры: общее число затраченных токенов, ответ модели, время генерации и время загрузки (в миллисекундах). Затем вычисляем скорость работы в токенах в секунду:
local total_tokens=$(jq -r '.eval_count // 0' "$response_file")
local model_response=$(jq -r '.response // ""' "$response_file")
local eval_sec=$(echo "$eval_duration_ns / 1000000000" | bc -l)
local load_sec=$(echo "$load_duration_ns / 1000000000" | bc -l)
local tokens_per_sec=0
if (( $(echo "$eval_sec > 0.001" | bc -l) )); then
tokens_per_sec=$(echo "scale=2; $total_tokens / $eval_sec" | bc)
fi
Потом красиво выводим всё на экран, добавляя вывод параметров от nvidia-smi:
nvidia-smi --query-gpu=index,name,memory.used,memory.total,temperature.gpu,power.draw,power.limit
Останавливаем тестирование тогда, когда происходит оффлоад на CPU.

Всё. Первая версия теста делала только это. Она работала, но аппетит обычно приходит во время еды. Поэтому коллеги попросили улучшить тест, и появилась вторая версия.
Вторая версия
Изменений во второй версии было внесено достаточно много. Начнем по порядку:
В первой версии бралась только одна модель, максимально подходящая по объему, а меньшие модели просто игнорировались. Но тогда невозможно сравнить различные конфигурации серверов с GPU, так как модели получались разные. По итогу были созданы два режима: max и test. В первом режиме тестирование осуществляется только с максимально «влазящей» в видеопамять моделью, а во втором идет тест по нарастающей всех моделей, начиная с самой маленькой.
Стартовый параметр контекста был увеличен до дефолтного для Ollama 4K.
Появилась возможность задавать свой промт, а не использовать дефолтный промт тетриса.
Теперь можно запустить конкретную модель из списка доступных.
Можно протестировать GPU с заданным значением контекста без его перебора.
Теперь можно выбрать другую группу моделей. Были добавлены опенсурсные модели от OpenAI и модели от Qwen.
В режиме test формируется итоговая таблица в HTML формате.
Все эти опции теперь доступны при запуске бенчмарка через передачу необходимых параметров:
Опции:
-t MODE Режим работы скрипта:
max — запустить одну максимально подходящую модель из группы и тестировать с увеличением контекста (режим по умолчанию)
test — протестировать все модели из группы от маленькой к большой
-p PROMPT Промт для генерации (по умолчанию: "Generate Tetris game on HTML and JS")
-m MODEL Запустить ТОЛЬКО указанную модель (игнорирует -t и -g)
-c CTX Использовать фиксированный размер контекста
-g GROUP Группа моделей: deepseekr1 (по умолчанию), gpt-oss, qwen3
-h Показать эту справку и выйти
Таблица доступных моделей приобрела следующий вид.
Модель |
Требуемый минимальный объем видеопамяти, ГиБ |
deepseek-r1:14b |
15 |
deepseek-r1:32b |
23 |
deepseek-r1:70b |
48 |
gpt-oss:20b |
16 |
gpt-oss:120b |
70 |
qwen3:14b |
15 |
qwen3:32b |
23 |
И она может быть легко изменена или расширена в будущем, так как задается следующим фрагментом скрипта:
declare -A MODEL_VRAM
MODEL_VRAM=(
["deepseek-r1:14b"]="15"
["deepseek-r1:32b"]="23"
["deepseek-r1:70b"]="48"
["gpt-oss:20b"]="16"
["gpt-oss:120b"]="70"
["qwen3:14b"]="15"
["qwen3:32b"]="23"
)
declare -A MODEL_GROUPS
MODEL_GROUPS["deepseekr1"]="deepseek-r1:14b deepseek-r1:32b deepseek-r1:70b"
MODEL_GROUPS["gpt-oss"]="gpt-oss:20b gpt-oss:120b"
MODEL_GROUPS["qwen3"]="qwen3:14b qwen3:32b"
По мелочи: улучшили форматирование и поправили мелкие баги, типа неверного определения установки Ollama, когда у нее не прописывались сервисы, или сбоев при определении offload режима.
Ниже пример вывода на экран теста второй версии:
=== [deepseek-r1:70b] Тест с num_ctx=30000 ===
Ollama PS:
NAME ID SIZE PROCESSOR CONTEXT UNTIL
deepseek-r1:70b d37b54d01a76 62 GB 100% GPU 30000 4 minutes from now
nvidia-smi:
GPU Name Mem used Mem total Temp Power draw Power lim
0 NVIDIA GeForce RTX 5090 31447 MiB 32607 MiB 63°C 340.80 W 575.00 W
1 NVIDIA GeForce RTX 5090 31179 MiB 32607 MiB 58°C 295.09 W 575.00 W
Результаты:
- Время загрузки: 17.687 сек
- Время генерации: 83.218 сек
- Токенов: 2752
- Скорость: 33.06 токенов/сек
- GPU загрузка: 100%
✅ Модель deepseek-r1:70b полностью протестирована.
? Готово. Результаты в /root/gpu_test/
Полный код скрипта можно посмотреть (и использовать у себя) в репозитории на GitHub.
Результаты
Тест-бенчмарк получился рабочий (хоть и не самый быстрый, прогон одной модели занимает минут 10), мы попробовали его на множестве наших GPU-серверов и в текущей реализации даже выявили интересные закономерности:
У Ollama не получается переносить нагрузку с одного на несколько GPU при увеличении ctx для небольших моделей. У нас маленькие модели при достижении объема памяти одного GPU просто вылетали с ошибкой.
Скорость работы с моделью не зависит от размера ctx при равных условиях. В среднем она постоянна.
Ollama не распараллеливает работу с нейросетевыми моделями, а просто перераспределяет их на весь доступный объем видеопамяти. То есть не нужно ожидать, что две NVIDIA RTX 5090 будут работать в два раза быстрее, чем один GPU. Нет. Скорости будут такими же.
Различные переменные окружения Ollama почти не влияют на итоговый результат. Мы смогли выжать максимум +1 токен в секунду.
Актуальную итоговую таблицу протестированных нами GPU (a4000, a5000, 4090, 5090, 2x4090 и 2x5090) в DeepSeek R1 с размером от 7 до 70B можно также посмотреть на github.

Сразу оговоримся, что так как развитие Ollama идет полным ходом, то у вас могут быть лучшие показатели. Мы будем рады, если вы попробуете наш тест и поделитесь его результатами с нами.
|
GPU-серверы — почасовая тарификация Мощные серверы с видеокартами NVIDIA последних поколений. Почасовая и помесячная оплата со скидкой. |