Кампания на пять равных долей: контейнер сразу считает свою часть

gen_scenarios.py раскладывает 115 прогонов по пяти долям (LPT, поправка
на размер сетки по замерам dzn) — по ≈24 ч каждая; поле shard в
scenarios.json. run_campaign.sh/.ps1 получили --shard. Новая точка входа
образа entrypoint.sh: при KBC2D_SHARD сама выбирает путь к карте (dzn
или NVIDIA), проверяет vulkaninfo и parity.py и запускает долю. Для
чужих ПК под Windows/WSL2 — docker-compose.shards.yml и shard.bat.
Образ notbigghost/kbc2d:1.3.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 20:15:40 +03:00
co-authored by Claude Opus 5.5
parent 3e81ed130c
commit 1d495e3e89
12 changed files with 582 additions and 130 deletions
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# Точка входа образа.
#
# Без KBC2D_SHARD — ровно прежнее поведение: аргументы уходят в run_campaign.sh, а по
# умолчанию (CMD --dry-run) печатается смета. Профили check в compose-файлах работают как раньше.
#
# С KBC2D_SHARD=K контейнер — одна из долей кампании, и считать он начинает сам, без ручной
# цепочки vulkan → parity → plan. Перед стартом три шага, каждый обрывает запуск с понятным
# сообщением, а не даёт кампании уйти считать впустую:
# 1. путь к карте: /dev/dxg есть — значит WSL2 или Docker Desktop, и работает dzn;
# нет — настоящий Linux, Vulkan-ICD подкладывает NVIDIA Container Toolkit;
# 2. vulkaninfo должен увидеть хотя бы один НЕпрограммный адаптер;
# 3. parity.py — сверка GPU с CPU-f64 на двух эталонах (~2 мин). Один раз на каталог out:
# после успеха кладётся маркер, и перезапуск контейнера её не повторяет.
set -u
cd "$(dirname "$0")"
[ -n "${KBC2D_SHARD:-}" ] || exec ./run_campaign.sh "$@"
K="$KBC2D_SHARD"
OUT="${KBC2D_OUT:-out}"
mkdir -p "$OUT"
say() { echo "[доля $K] $*"; }
die() { echo; echo "[доля $K] ОСТАНОВЛЕНО: $*" >&2; exit 3; }
# ── 1. путь к карте ──────────────────────────────────────────────────────────
if [ -e /dev/dxg ]; then
say "найден /dev/dxg — WSL2 / Docker Desktop, Vulkan через dzn (Vulkan → D3D12)"
[ -d /usr/lib/wsl/lib ] || die "нет /usr/lib/wsl/lib: смонтируйте /usr/lib/wsl:/usr/lib/wsl:ro
(в docker-compose.shards.yml это уже прописано)"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-/usr/lib/wsl/lib}"
# dzn сообщает conformanceVersion 0.0.0.0, и без согласия wgpu его прячет. Согласие
# оправдано только потому, что шаг 3 ниже проверяет числа.
export WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER="${WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER:-1}"
else
say "/dev/dxg нет — нативный Linux, Vulkan-драйвер NVIDIA от Container Toolkit"
fi
# ── 2. видна ли карта ────────────────────────────────────────────────────────
info=$(vulkaninfo --summary 2>&1)
gpus=$(printf '%s\n' "$info" | grep -E 'deviceType *=' | grep -vc 'PHYSICAL_DEVICE_TYPE_CPU')
if [ "$gpus" -lt 1 ]; then
printf '%s\n' "$info" | tail -20 >&2
die "Vulkan не видит ни одной видеокарты. Что проверить на хосте:
* Windows / WSL2: драйвер видеокарты под Windows установлен и свежий; Docker Desktop
работает на бэкенде WSL2; контейнеру проброшены /dev/dxg и /usr/lib/wsl.
* Linux: установлен nvidia-container-toolkit, контейнер запущен с GPU, и в
NVIDIA_DRIVER_CAPABILITIES есть graphics (сейчас: ${NVIDIA_DRIVER_CAPABILITIES:-не задано})."
fi
printf '%s\n' "$info" | grep -E 'deviceName *=|driverName *=|deviceType *=' | sed 's/^ */ /'
# ── 3. считает ли карта правильно ────────────────────────────────────────────
mark="$OUT/parity_shard$K.ok"
if [ -f "$mark" ]; then
say "сверка GPU с CPU уже пройдена ранее ($mark)"
else
say "сверка GPU с CPU-эталоном (parity.py, около двух минут)…"
python3 parity.py || die "GPU расходится с CPU-эталоном — результаты этой машины нечем
защищать. Вывод сверки выше. Повторить: удалить контейнер и поднять заново."
date -Is > "$mark"
fi
# ── кампания ─────────────────────────────────────────────────────────────────
say "старт: run_campaign.sh --resume --shard $K"
exec ./run_campaign.sh --resume --shard "$K" "$@"