diff --git a/docs/theory/2d_solver/Dockerfile b/docs/theory/2d_solver/Dockerfile index f6a645e..7eff2b5 100644 --- a/docs/theory/2d_solver/Dockerfile +++ b/docs/theory/2d_solver/Dockerfile @@ -28,8 +28,16 @@ RUN touch src/main.rs && cargo build --release --locked # ── исполнение ─────────────────────────────────────────────────────────────── FROM debian:bookworm-slim + +# Версия и коммит приходят снаружи (см. bench/publish.sh): образ на сервере должен +# однозначно сопоставляться с состоянием репозитория, из которого собран. +ARG VERSION=dev +ARG REVISION=unknown LABEL org.opencontainers.image.title="kbc2d" LABEL org.opencontainers.image.description="Двумерный решатель LBM D2Q9 с энтропийным столкновением KBC" +LABEL org.opencontainers.image.version="${VERSION}" +LABEL org.opencontainers.image.revision="${REVISION}" +LABEL org.opencontainers.image.source="https://gitea.arseniev.info/NotBigGhost/TurbulenceCAD" RUN apt-get update && apt-get install -y --no-install-recommends \ libvulkan1 vulkan-tools python3 ca-certificates \ diff --git a/docs/theory/2d_solver/README.md b/docs/theory/2d_solver/README.md index 45acd7f..6966edb 100644 --- a/docs/theory/2d_solver/README.md +++ b/docs/theory/2d_solver/README.md @@ -492,14 +492,38 @@ python preflight.py # каждый сценарий старту ## Развёртывание (Docker) +Собранный образ опубликован: **`notbigghost/kbc2d:1.0.0`** (он же `latest`, он же по хешу +коммита `8d17bc8`; все три тега — один digest `sha256:932d881d…`, платформа `linux/amd64`). +Исходники на сервере не нужны — достаточно перенести туда один файл +`docker-compose.server.yml`: + +```sh +mkdir -p ~/kbc2d && cd ~/kbc2d # сюда же ляжет ./out с результатами +# перенести docker-compose.server.yml + +docker compose -f docker-compose.server.yml --profile check run --rm vulkan # карта видна? +docker compose -f docker-compose.server.yml --profile check run --rm preflight # сценарии стартуют? +docker compose -f docker-compose.server.yml --profile check run --rm calibrate # сколько MLUPS? +docker compose -f docker-compose.server.yml up -d # кампания +docker compose -f docker-compose.server.yml logs -f +``` + +Порядок именно такой: узнать, что карта не видна, лучше через минуту, чем через час. Замеренные +`--calibrate` числа подставляются переменными `KBC2D_GPU_MLUPS` / `KBC2D_CPU_MLUPS` — только на +оценки в часах, на счёт они не влияют. + +Собрать образ самому (`docker-compose.yml` рядом делает то же самое с `build:`): + ```sh docker build -t kbc2d docs/theory/2d_solver -docker run --rm --gpus all kbc2d --calibrate # проверить, что GPU виден -docker run -d --gpus all -v "$PWD/out:/work/bench/out" kbc2d --resume +docker run --rm --gpus all kbc2d --calibrate ``` `ENTRYPOINT` — драйвер кампании, `CMD` по умолчанию `--dry-run`: случайный `docker run` покажет -смету и выйдет, а не запустит сточасовую задачу. +смету и выйдет, а не запустит сточасовую задачу. В серверном compose политика перезапуска — +`on-failure`, а не `unless-stopped`: кампания завершается штатно с кодом 0, и «перезапускать +всегда» крутило бы контейнер вхолостую по кругу, тогда как падение или перезагрузку хоста +`on-failure` подхватывает, а `--resume` продолжает с места. **Главная тонкость — Vulkan внутри контейнера.** NVIDIA Container Toolkit подкладывает Vulkan-ICD (`nvidia_icd.json`) только если в `NVIDIA_DRIVER_CAPABILITIES` есть `graphics`; diff --git a/docs/theory/2d_solver/bench/README.md b/docs/theory/2d_solver/bench/README.md index 61318b8..00720fa 100644 --- a/docs/theory/2d_solver/bench/README.md +++ b/docs/theory/2d_solver/bench/README.md @@ -6,23 +6,49 @@ ## Быстрый старт на сервере -```sh -docker build -t kbc2d docs/theory/2d_solver -docker run --rm --gpus all --entrypoint python3 kbc2d preflight.py # сценарии стартуют -docker run --rm --gpus all kbc2d --calibrate # GPU виден -docker run -d --gpus all -v "$PWD/out:/work/bench/out" --name kbc2d kbc2d --resume -docker logs -f kbc2d -``` - -Первым делом стоит убедиться, что Vulkan внутри контейнера действительно видит карту: +Образ опубликован, собирать ничего не нужно: **`notbigghost/kbc2d:1.0.0`**. Исходники на +сервере тоже не нужны — переносится один файл `docker-compose.server.yml`. ```sh -docker run --rm --gpus all --entrypoint vulkaninfo kbc2d --summary | head -20 +mkdir -p ~/kbc2d && cd ~/kbc2d # сюда же ляжет ./out с результатами +# перенести сюда docker-compose.server.yml + +C=docker-compose.server.yml +docker compose -f $C --profile check run --rm vulkan # 1. карта видна из контейнера? +docker compose -f $C --profile check run --rm preflight # 2. все 115 сценариев стартуют? +docker compose -f $C --profile check run --rm calibrate # 3. сколько MLUPS на этой машине? +docker compose -f $C --profile check run --rm plan # 4. смета в часах по замеренному +docker compose -f $C up -d # 5. кампания +docker compose -f $C logs -f ``` -Если адаптеров ноль — почти наверняка дело в `NVIDIA_DRIVER_CAPABILITIES`: Container Toolkit -подкладывает Vulkan-ICD только при наличии `graphics` в списке. В образе это прописано, но -может быть переопределено снаружи. +Порядок не случайный: узнать, что карта не видна, лучше на первом шаге, чем через час счёта. + +Замеренные калибровкой числа подставляются переменными окружения — они влияют только на +оценки в часах, не на счёт: + +```sh +KBC2D_GPU_MLUPS=1450 KBC2D_CPU_MLUPS=40 docker compose -f $C --profile check run --rm plan +``` + +**Если `vulkaninfo` показывает ноль адаптеров** — почти наверняка дело в +`NVIDIA_DRIVER_CAPABILITIES`: Container Toolkit подкладывает Vulkan-ICD только при наличии +`graphics` в списке. В образе и в compose это прописано, но может быть переопределено снаружи. +Проверить, что хост вообще умеет отдавать карту: + +```sh +docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi +``` + +## Своя сборка образа + +Если нужен образ из текущего состояния репозитория, а не опубликованный: + +```sh +docker build -t kbc2d docs/theory/2d_solver --build-arg VERSION=dev --build-arg REVISION=$(git rev-parse --short HEAD) +``` + +Рядом лежит `docker-compose.yml` — то же самое через `build:`, для локальной отладки. ## Без Docker diff --git a/docs/theory/2d_solver/docker-compose.server.yml b/docs/theory/2d_solver/docker-compose.server.yml new file mode 100644 index 0000000..f7eb91e --- /dev/null +++ b/docs/theory/2d_solver/docker-compose.server.yml @@ -0,0 +1,97 @@ +# Развёртывание кампании на сервере с NVIDIA. Этот файл САМОДОСТАТОЧЕН: он тянет готовый образ +# из реестра и исходников репозитория не требует. Скопировать на сервер достаточно его одного. +# +# mkdir -p ~/kbc2d && cd ~/kbc2d +# curl -O <ссылка на этот файл> # либо просто перенести файл руками +# +# docker compose -f docker-compose.server.yml --profile check run --rm vulkan +# docker compose -f docker-compose.server.yml --profile check run --rm preflight +# docker compose -f docker-compose.server.yml --profile check run --rm calibrate +# docker compose -f docker-compose.server.yml --profile check run --rm plan +# docker compose -f docker-compose.server.yml up -d +# docker compose -f docker-compose.server.yml logs -f +# +# Порядок именно такой. Сначала vulkan: если карта не видна, кампания молча уйдёт считать +# ничего — точнее, откажется стартовать на первом же прогоне, но узнать об этом через час +# обиднее, чем через минуту. Потом preflight (каждый сценарий стартует на два шага), потом +# calibrate (замер MLUPS этой машины), и только потом сама кампания. +# +# Результаты складываются в ./out на хосте — около 4.4 ГБ гифок и рядов за полный проход. + +name: kbc2d + +# ── общая часть всех сервисов ──────────────────────────────────────────────── +x-kbc2d: &kbc2d + image: notbigghost/kbc2d:1.0.0 + pull_policy: missing + volumes: + - ./out:/work/bench/out + environment: + # ГЛАВНОЕ МЕСТО ВСЕГО ФАЙЛА. NVIDIA Container Toolkit подкладывает внутрь Vulkan-ICD + # (nvidia_icd.json) только если в этом списке есть `graphics`. С одним `compute` wgpu не + # увидит НИ ОДНОГО адаптера, и решатель откажется стартовать с --backend gpu. В образе + # значение уже прописано, здесь оно продублировано явно — чтобы его было видно тому, кто + # читает compose, а не Dockerfile. + NVIDIA_DRIVER_CAPABILITIES: compute,utility,graphics + NVIDIA_VISIBLE_DEVICES: all + # Оценки в часах драйвер считает из этих чисел. Умолчания взяты с другой машины — + # подставьте сюда то, что напечатает профиль calibrate. + KBC2D_GPU_MLUPS: ${KBC2D_GPU_MLUPS:-1200} + KBC2D_CPU_MLUPS: ${KBC2D_CPU_MLUPS:-22} + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + +services: + # ── сама кампания: единственный сервис, который поднимается по `up -d` ────── + campaign: + <<: *kbc2d + container_name: kbc2d-campaign + # --resume пропускает всё, у чего уже есть summary.json: перезапуск продолжает с места, + # а не начинает заново. Именно поэтому перезапуск здесь безопасен и дёшев. + command: ["--resume"] + # on-failure, а НЕ unless-stopped: кампания завершается штатно с кодом 0, и политика + # «перезапускать всегда» после её окончания крутила бы контейнер вхолостую по кругу. + # Падение (OOM, перезагрузка хоста) даёт ненулевой код и будет подхвачено. + restart: on-failure:5 + stop_grace_period: 30s + # Девяносто часов вывода — это сотни мегабайт журнала; без ограничения он съест диск. + # Полные логи каждого прогона всё равно лежат в out//log.txt. + logging: + driver: json-file + options: + max-size: "50m" + max-file: "5" + + # ── проверки перед запуском (профиль check, сами не поднимаются) ──────────── + vulkan: + <<: *kbc2d + profiles: ["check"] + entrypoint: ["vulkaninfo"] + command: ["--summary"] + + preflight: + <<: *kbc2d + profiles: ["check"] + entrypoint: ["python3"] + command: ["preflight.py"] + + calibrate: + <<: *kbc2d + profiles: ["check"] + command: ["--calibrate"] + + plan: + <<: *kbc2d + profiles: ["check"] + command: ["--dry-run"] +# ── если результаты нужны не под root ──────────────────────────────────────── +# Контейнер работает от root, поэтому файлы в ./out окажутся root:root. Чтобы они +# принадлежали вам, добавьте в x-kbc2d строку +# user: "${UID}:${GID}" +# и запускайте как UID=$(id -u) GID=$(id -g) docker compose -f … up -d +# (каталог ./out при этом должен быть создан заранее и принадлежать вам).