diff --git a/docs/theory/2d_solver/Dockerfile b/docs/theory/2d_solver/Dockerfile index 117b8cc..69181fc 100644 --- a/docs/theory/2d_solver/Dockerfile +++ b/docs/theory/2d_solver/Dockerfile @@ -70,10 +70,12 @@ ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility,graphics WORKDIR /work COPY --from=build /src/target/release/kbc2d /work/target/release/kbc2d COPY bench /work/bench -RUN chmod +x /work/bench/run_campaign.sh +RUN chmod +x /work/bench/run_campaign.sh /work/bench/entrypoint.sh # Кампания идёт десятки часов, поэтому по умолчанию образ НЕ запускает её: случайный -# `docker run` покажет смету и выйдет. +# `docker run` покажет смету и выйдет. Иначе — если задана доля (KBC2D_SHARD=1..5, так делает +# docker-compose.shards.yml): тогда entrypoint.sh сам проверяет карту, сверяет её с CPU и +# сразу начинает считать свою часть. WORKDIR /work/bench -ENTRYPOINT ["./run_campaign.sh"] +ENTRYPOINT ["./entrypoint.sh"] CMD ["--dry-run"] diff --git a/docs/theory/2d_solver/README.md b/docs/theory/2d_solver/README.md index 0a4ba72..a0ddec1 100644 --- a/docs/theory/2d_solver/README.md +++ b/docs/theory/2d_solver/README.md @@ -497,7 +497,7 @@ python preflight.py # каждый сценарий старту ## Развёртывание (Docker) -Собранный образ опубликован: **`notbigghost/kbc2d:1.2.0`** (он же `latest`, платформа `linux/amd64`). +Собранный образ опубликован: **`notbigghost/kbc2d:1.3.0`** (он же `latest`, платформа `linux/amd64`). Исходники на сервере не нужны — достаточно перенести туда один файл `docker-compose.server.yml`: @@ -523,7 +523,17 @@ docker build -t kbc2d docs/theory/2d_solver docker run --rm --gpus all kbc2d --calibrate ``` -`ENTRYPOINT` — драйвер кампании, `CMD` по умолчанию `--dry-run`: случайный `docker run` покажет +### Пять долей на пяти машинах + +Кампания разложена на **пять равных по времени долей** (≈24 ч каждая, поле `shard` в +`scenarios.json`), чтобы считать её одновременно на пяти чужих ПК с видеокартой под Windows +или WSL2. На машину переносятся два файла — `docker-compose.shards.yml` и `shard.bat` — и +выполняется `shard.bat 3` (или `docker compose -f docker-compose.shards.yml up -d shard3`). +Контейнер сам проверяет карту, сверяет её с CPU-эталоном и сразу считает свою долю. Подробно — +`bench/README.md`, раздел «Пять долей». + +`ENTRYPOINT` — `bench/entrypoint.sh`. Без `KBC2D_SHARD` он просто передаёт аргументы драйверу +кампании, и `CMD` по умолчанию `--dry-run`: случайный `docker run` покажет смету и выйдет, а не запустит сточасовую задачу. В серверном compose политика перезапуска — `on-failure`, а не `unless-stopped`: кампания завершается штатно с кодом 0, и «перезапускать всегда» крутило бы контейнер вхолостую по кругу, тогда как падение или перезагрузку хоста diff --git a/docs/theory/2d_solver/bench/README.md b/docs/theory/2d_solver/bench/README.md index fc8ba9d..b3fa08d 100644 --- a/docs/theory/2d_solver/bench/README.md +++ b/docs/theory/2d_solver/bench/README.md @@ -6,9 +6,67 @@ схемы. Каждый прогон кладёт в собственную папку `cmd.txt`, `log.txt`, `report.txt`, `series.csv` и `summary.json`; гифку пишут **59 прогонов из 115** — остальным `--gif` не передаётся. +## Пять долей: чужие ПК под Windows / WSL2 + +Кампания разложена на **пять долей, равных по времени**: у каждого прогона в `scenarios.json` +есть поле `shard` (1…5). Каждая доля — отдельный контейнер, который при развёртывании **сразу +начинает считать**: ни сборки, ни ручной цепочки проверок, всё окружение (решатель, Vulkan- +загрузчик, dzn, Python) — внутри образа. + +На машину переносятся два файла из корня решателя — `docker-compose.shards.yml` и `shard.bat`: + +```bat +shard.bat 3 +``` + +или из любой оболочки: + +```sh +docker compose -f docker-compose.shards.yml up -d shard3 +docker compose -f docker-compose.shards.yml logs -f shard3 +``` + +При старте контейнер (`entrypoint.sh`) сам делает то, что раньше делалось профилями check: + +1. выбирает путь к карте — есть `/dev/dxg`, значит WSL2 / Docker Desktop и dzn; нет — + нативный Linux с NVIDIA Container Toolkit; +2. проверяет `vulkaninfo`: нужен хотя бы один не программный адаптер; +3. гоняет `parity.py` (~2 мин) и только при совпадении с CPU-эталоном идёт дальше; после + успеха кладёт `out/parity_shardN.ok`, и перезапуск сверку не повторяет; +4. `run_campaign.sh --resume --shard N`. + +Любой провал на шагах 1–3 останавливает контейнер с объяснением, что поправить на хосте, — а +не отдаёт кампанию считать впустую. + +**В контейнер нельзя положить** драйвер видеокарты: он должен стоять в самой Windows (Vulkan +внутри контейнера — это dzn, транслирующий вызовы в D3D12 драйвера хоста). И нужен Docker +Desktop с бэкендом WSL2 (так по умолчанию) либо Docker внутри WSL2. + +| доля | прогонов | ≈ часов | +|---|---|---| +| 1 | 22 | 24.0 | +| 2 | 23 | 24.0 | +| 3 | 23 | 24.0 | +| 4 | 23 | 24.0 | +| 5 | 24 | 24.0 | + +Часы — оценка при 1200 MLUPS на крупной сетке **с поправкой на размер сетки**: на dzn мелкие +сетки считаются медленнее на узел, а сверхмелкие из группы I идут через раздельные привязки +(кривая — `DZN_MLUPS` в `gen_scenarios.py`, по замерам из раздела «Чего трансляция стоит по +скорости»). Раскладка жадная: самый долгий прогон — в самую лёгкую долю. Девять прогонов +группы I (по ≈8.7 ч) разошлись по два на долю в четырёх долях, пятая получила один и добрала остальным. +Равенство долей — равенство на **одинаковых** картах: на разных доли закончатся в разное время. +Абсолютные часы на конкретной карте — `--dry-run --shard N` после `--calibrate`. + +Пересобрать раскладку под другое число машин: `python gen_scenarios.py --shards 3`. + +**Сбор результатов.** Каждая доля пишет в `./out` рядом с compose-файлом: каталоги прогонов +`out//` (уникальны по id), свою сводку `summary_shardN.csv` и свой журнал +`campaign_shardN.log`. Собрать кампанию целиком — скопировать все пять `out/` в одну папку. + ## Быстрый старт на сервере -Образ опубликован, собирать ничего не нужно: **`notbigghost/kbc2d:1.2.0`**. Исходники на +Образ опубликован, собирать ничего не нужно: **`notbigghost/kbc2d:1.3.0`**. Исходники на сервере тоже не нужны — переносится один файл `docker-compose.server.yml`. ```sh @@ -186,6 +244,7 @@ KBC2D_GPU_MLUPS=1400 ./run_campaign.sh --dry-run | `--group A,B` | только выбранные группы | | `--only cyl_re150` | по подстроке идентификатора | | `--budget-hours 24` | остановиться, когда время выйдет | +| `--shard 3` | только доля 3 (поле `shard` в `scenarios.json`); то же — переменная `KBC2D_SHARD` | Прогон, который упал или развалился, помечается в сводке и **не останавливает кампанию**: группы E и G специально ищут предел устойчивости, там развал — ожидаемый результат. diff --git a/docs/theory/2d_solver/bench/entrypoint.sh b/docs/theory/2d_solver/bench/entrypoint.sh new file mode 100644 index 0000000..6a27e06 --- /dev/null +++ b/docs/theory/2d_solver/bench/entrypoint.sh @@ -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" "$@" diff --git a/docs/theory/2d_solver/bench/gen_scenarios.py b/docs/theory/2d_solver/bench/gen_scenarios.py index 33b34fe..6ace5f3 100644 --- a/docs/theory/2d_solver/bench/gen_scenarios.py +++ b/docs/theory/2d_solver/bench/gen_scenarios.py @@ -5,6 +5,7 @@ # получаются циклами, а стоимость каждого прогона считается тут же и суммируется. Запуск: # python gen_scenarios.py # перезаписать scenarios.json и напечатать смету # python gen_scenarios.py --scale 2 # растянуть все длительности вдвое +# python gen_scenarios.py --shards 5 # на сколько равных по времени долей делить кампанию # # Стоимость меряется в ОБНОВЛЕНИЯХ УЗЛОВ (nodes_per_step * steps) — единственная переносимая # между машинами мера. Часы драйвер получает из неё, поделив на фактические MLUPS, которые @@ -23,6 +24,18 @@ GIF_MAX_W = 1280 # предельная ширина кадра после GIF_MIN_W = 480 # ниже не опускаемся: нечитаемая гифка бесполезнее большой GIF_PX_BUDGET = 1.5e9 # кадры×пиксели на гифку; при 0.103 байта на пиксель это ~150 МБ +# Доли кампании: прогоны раскладываются по N контейнерам так, чтобы те считали примерно +# одинаковое ВРЕМЯ, а не одинаковое число узлов. Время на узел зависит от размера сетки: +# на мелкой накладные расходы на отправку в очередь дороже самого счёта. Кривая — замер +# dzn в контейнере (Intel Iris Xe, bench/README.md, «Чего трансляция стоит по скорости»), +# потому что доли рассчитаны на чужие Windows/WSL-машины, где путь к карте — именно dzn. +# Важна только ФОРМА кривой: абсолют нормируется к ASSUMED_GPU_MLUPS. +ASSUMED_GPU_MLUPS = 1200 +ASSUMED_CPU_MLUPS = 22 +DZN_MLUPS = [(61_440, 44.5), (460_800, 86.0), (1_843_200, 98.7)] +SPLIT_NODES = 3_730_000 # выше — раздельные привязки популяций, у них своя скорость +SPLIT_MLUPS = 67.4 # замер на 2048×2048 + def conv_steps(d_cells, n_conv, u_lat=U_LAT): """Сколько шагов нужно на n_conv конвективных времён D/U.""" @@ -472,15 +485,50 @@ def group_i(scale): nx * ny, st, gif="fine_multi.gif", nx=nx) +def est_hours(r): + """Оценка времени прогона в часах для раскладки по долям (см. DZN_MLUPS).""" + if r["backend"] == "cpu": + return r["cost"] / (ASSUMED_CPU_MLUPS * 1e6) / 3600 + n = r["nodes_per_step"] + if n > SPLIT_NODES: + m = SPLIT_MLUPS + elif n <= DZN_MLUPS[0][0]: + m = DZN_MLUPS[0][1] + elif n >= DZN_MLUPS[-1][0]: + m = DZN_MLUPS[-1][1] + else: + for (n0, m0), (n1, m1) in zip(DZN_MLUPS, DZN_MLUPS[1:]): + if n <= n1: + t = math.log(n / n0) / math.log(n1 / n0) + m = m0 + t * (m1 - m0) + break + rel = m / DZN_MLUPS[-1][1] + return r["cost"] / (ASSUMED_GPU_MLUPS * 1e6 * rel) / 3600 + + +def assign_shards(runs, n): + """Разложить прогоны по n долям жадно (LPT): самый долгий — в самую лёгкую долю. + Порядок прогонов внутри доли остаётся порядком групп. Возвращает часы по долям.""" + load = [0.0] * n + for r in sorted(runs, key=lambda r: (-est_hours(r), r["id"])): + k = min(range(n), key=lambda i: load[i]) + r["shard"] = k + 1 + load[k] += est_hours(r) + return load + + def main(): ap = argparse.ArgumentParser() ap.add_argument("--scale", type=float, default=2.0, help="общий множитель длительности всех прогонов") + ap.add_argument("--shards", type=int, default=5, + help="на сколько равных по времени долей делить кампанию") ap.add_argument("--out", default=os.path.join(os.path.dirname(__file__), "scenarios.json")) args = ap.parse_args() for g in (group_a, group_b, group_c, group_d, group_e, group_f, group_g, group_h, group_i): g(args.scale) + shard_hours = assign_shards(RUNS, args.shards) doc = { "meta": { @@ -490,12 +538,14 @@ def main(): "gif_policy": "вся длительность прогона, реальная скорость, 10 кадр/с; кадр " "прореживается до ширины не больше 1280 пикселей", "scale": args.scale, - "assumed_gpu_mlups": 1200, - "assumed_cpu_mlups": 22, + "assumed_gpu_mlups": ASSUMED_GPU_MLUPS, + "assumed_cpu_mlups": ASSUMED_CPU_MLUPS, + "shards": args.shards, + "shard_hours": [round(h, 2) for h in shard_hours], }, "runs": RUNS, } - with open(args.out, "w", encoding="utf-8") as f: + with open(args.out, "w", encoding="utf-8", newline="\n") as f: json.dump(doc, f, ensure_ascii=False, indent=1) print(f"прогонов: {len(RUNS)} файл: {args.out}\n") @@ -513,6 +563,12 @@ def main(): f"{tot_gpu:>12.1f}{tot_cpu:>12.1f}") print(f"\nвсего ≈ {tot_gpu + tot_cpu:.1f} ч при 1200 MLUPS на GPU и 22 на CPU") + print("\nдоли (часы с поправкой на размер сетки, см. DZN_MLUPS):") + for k, h in enumerate(shard_hours, 1): + n = sum(1 for r in RUNS if r["shard"] == k) + print(f" доля {k}: {n:>3} прогонов ≈ {h:5.1f} ч") + print(f" разброс: {(max(shard_hours) / min(shard_hours) - 1) * 100:.1f} %") + if __name__ == "__main__": main() diff --git a/docs/theory/2d_solver/bench/run_campaign.ps1 b/docs/theory/2d_solver/bench/run_campaign.ps1 index 6eccc45..84e4017 100644 --- a/docs/theory/2d_solver/bench/run_campaign.ps1 +++ b/docs/theory/2d_solver/bench/run_campaign.ps1 @@ -7,6 +7,7 @@ # .\run_campaign.ps1 -Smoke # .\run_campaign.ps1 -Resume -Group A,B # .\run_campaign.ps1 -Only cyl_re150 -BudgetHours 6 +# .\run_campaign.ps1 -Resume -Shard 3 [CmdletBinding()] param( @@ -16,6 +17,7 @@ param( [switch]$Smoke, [string[]]$Group, [string]$Only, + [int]$Shard = 0, [double]$BudgetHours = 0, [string]$Bin = "..\target\release\kbc2d.exe", [string]$Scenarios = "scenarios.json", @@ -45,6 +47,7 @@ if ($Calibrate) { $runs = (Get-Content $Scenarios -Raw -Encoding UTF8 | ConvertFrom-Json).runs if ($Group) { $g = $Group | ForEach-Object { $_.ToUpper() }; $runs = $runs | Where-Object { $g -contains $_.group.ToUpper() } } +if ($Shard) { $runs = $runs | Where-Object { $_.shard -eq $Shard } } if ($Only) { $runs = $runs | Where-Object { $_.id -like "*$Only*" } } if ($Smoke) { $runs = $runs | Sort-Object cost | Select-Object -First 3 } if (-not $runs) { "под выборку не попал ни один прогон"; return } @@ -67,6 +70,11 @@ if ($DryRun) { New-Item -ItemType Directory -Force $Out | Out-Null $summary = Join-Path $Out 'summary.csv' $log = Join-Path $Out 'campaign.log' +# у каждой доли своя сводка и свой журнал, как в run_campaign.sh +if ($Shard) { + $summary = Join-Path $Out "summary_shard$Shard.csv" + $log = Join-Path $Out "campaign_shard$Shard.log" +} if (-not (Test-Path $summary)) { 'id,group,backend,status,seconds,steps,cost,title' | Out-File $summary -Encoding utf8 } $started = Get-Date diff --git a/docs/theory/2d_solver/bench/run_campaign.sh b/docs/theory/2d_solver/bench/run_campaign.sh index 2c4e4d8..86c99a9 100644 --- a/docs/theory/2d_solver/bench/run_campaign.sh +++ b/docs/theory/2d_solver/bench/run_campaign.sh @@ -9,6 +9,7 @@ # ./run_campaign.sh --group A,B только выбранные группы # ./run_campaign.sh --only cyl_re150 по подстроке идентификатора # ./run_campaign.sh --budget-hours 24 остановиться, когда время выйдет +# ./run_campaign.sh --shard 3 только доля 3 из scenarios.json (или KBC2D_SHARD=3) # # Прогон, который упал или развалился, помечается в сводке и НЕ останавливает кампанию: # группы E и G специально ищут предел устойчивости. @@ -23,6 +24,7 @@ OUT="${KBC2D_OUT:-out}" # молча игнорируется, а "$GROUPS" под root разворачивается в 0 — и выборка съедает всю # кампанию, не сказав ни слова. Отсюда GRP_SEL. DRY=0; RESUME=0; CALIB=0; SMOKE=0; GRP_SEL=""; ONLY=""; BUDGET="" +SHARD="${KBC2D_SHARD:-}" GPU_MLUPS="${KBC2D_GPU_MLUPS:-1200}" CPU_MLUPS="${KBC2D_CPU_MLUPS:-22}" @@ -35,7 +37,8 @@ while [ $# -gt 0 ]; do --group) GRP_SEL="$2"; shift ;; --only) ONLY="$2"; shift ;; --budget-hours) BUDGET="$2"; shift ;; - -h|--help) sed -n '2,20p' "$0"; exit 0 ;; + --shard) SHARD="$2"; shift ;; + -h|--help) sed -n '2,21p' "$0"; exit 0 ;; *) echo "неизвестный ключ: $1" >&2; exit 2 ;; esac shift @@ -65,13 +68,22 @@ fi mkdir -p "$OUT" SUMMARY="$OUT/summary.csv" LOG="$OUT/campaign.log" +# У каждой доли своя сводка и свой журнал: папки out/ с разных машин сливаются простым +# копированием (каталоги прогонов уникальны по id), а доли на одной машине не пишут в один файл. +if [ -n "$SHARD" ]; then + SUMMARY="$OUT/summary_shard$SHARD.csv" + LOG="$OUT/campaign_shard$SHARD.log" +fi [ -f "$SUMMARY" ] || echo "id,group,backend,status,seconds,steps,cost,title" > "$SUMMARY" # Выборку и порядок считает python: разбирать JSON башем — верный способ ошибиться. -PLAN=$("$PY" - "$SCEN" "$GRP_SEL" "$ONLY" "$SMOKE" <<'PYEOF' +PLAN=$("$PY" - "$SCEN" "$GRP_SEL" "$ONLY" "$SMOKE" "$SHARD" <<'PYEOF' import json, sys scen, groups, only, smoke = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4] == "1" +shard = sys.argv[5] runs = json.load(open(scen, encoding="utf-8"))["runs"] +if shard: + runs = [r for r in runs if str(r.get("shard")) == shard] if groups: keep = {g.strip().upper() for g in groups.split(",")} runs = [r for r in runs if r["group"].upper() in keep] diff --git a/docs/theory/2d_solver/bench/scenarios.json b/docs/theory/2d_solver/bench/scenarios.json index 9b6099d..42f637a 100644 --- a/docs/theory/2d_solver/bench/scenarios.json +++ b/docs/theory/2d_solver/bench/scenarios.json @@ -4,7 +4,15 @@ "gif_policy": "вся длительность прогона, реальная скорость, 10 кадр/с; кадр прореживается до ширины не больше 1280 пикселей", "scale": 2.0, "assumed_gpu_mlups": 1200, - "assumed_cpu_mlups": 22 + "assumed_cpu_mlups": 22, + "shards": 5, + "shard_hours": [ + 24.0, + 24.0, + 24.0, + 24.0, + 24.0 + ] }, "runs": [ { @@ -40,7 +48,8 @@ "cost": 901120, "outputs": [ "case_csv" - ] + ], + "shard": 1 }, { "id": "A02_tg_diff_n128", @@ -75,7 +84,8 @@ "cost": 14434304, "outputs": [ "case_csv" - ] + ], + "shard": 5 }, { "id": "A03_tg_diff_n256", @@ -110,7 +120,8 @@ "cost": 231014400, "outputs": [ "case_csv" - ] + ], + "shard": 2 }, { "id": "A04_tg_diff_n512", @@ -145,7 +156,8 @@ "cost": 3696492544, "outputs": [ "case_csv" - ] + ], + "shard": 1 }, { "id": "A05_tg_fixed_n128", @@ -180,7 +192,8 @@ "cost": 14434304, "outputs": [ "case_csv" - ] + ], + "shard": 5 }, { "id": "A06_tg_fixed_n256", @@ -215,7 +228,8 @@ "cost": 231014400, "outputs": [ "case_csv" - ] + ], + "shard": 5 }, { "id": "A07_shear_n512_kbc_n1", @@ -268,7 +282,8 @@ "cost": 26843545600, "outputs": [ "case_csv" - ] + ], + "shard": 1 }, { "id": "A08_shear_n512_kbc_n2", @@ -321,7 +336,8 @@ "cost": 26843545600, "outputs": [ "case_csv" - ] + ], + "shard": 4 }, { "id": "A09_shear_n512_lbgk", @@ -374,7 +390,8 @@ "cost": 26843545600, "outputs": [ "case_csv" - ] + ], + "shard": 1 }, { "id": "A10_turb_n2048_kbc", @@ -425,7 +442,8 @@ "cost": 1677721600000, "outputs": [ "case_csv" - ] + ], + "shard": 3 }, { "id": "A11_turb_n2048_bgk", @@ -476,7 +494,8 @@ "cost": 1677721600000, "outputs": [ "case_csv" - ] + ], + "shard": 5 }, { "id": "A12_turb_n4096_kbc", @@ -527,7 +546,8 @@ "cost": 3355443200000, "outputs": [ "case_csv" - ] + ], + "shard": 4 }, { "id": "B01_cyl_re20", @@ -574,7 +594,8 @@ "nodes_per_step": 552960, "steps": 115200, "cost": 63700992000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "B02_cyl_re40", @@ -621,7 +642,8 @@ "nodes_per_step": 552960, "steps": 115200, "cost": 63700992000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "B03_cyl_re100", @@ -668,7 +690,8 @@ "nodes_per_step": 983040, "steps": 3840000, "cost": 3774873600000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "B04_cyl_re150", @@ -715,7 +738,8 @@ "nodes_per_step": 983040, "steps": 3840000, "cost": 3774873600000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "B05_cyl_re200", @@ -762,7 +786,8 @@ "nodes_per_step": 983040, "steps": 3840000, "cost": 3774873600000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "B06_cyl_re300", @@ -809,7 +834,8 @@ "nodes_per_step": 983040, "steps": 3840000, "cost": 3774873600000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "B07_cyl_d16", @@ -856,7 +882,8 @@ "nodes_per_step": 61440, "steps": 512000, "cost": 31457280000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "B08_cyl_d32", @@ -903,7 +930,8 @@ "nodes_per_step": 245760, "steps": 1024000, "cost": 251658240000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "B09_cyl_d64", @@ -950,7 +978,8 @@ "nodes_per_step": 983040, "steps": 2048000, "cost": 2013265920000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "B10_cyl_d128", @@ -997,7 +1026,8 @@ "nodes_per_step": 3932160, "steps": 4096000, "cost": 16106127360000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "B11_cyl_block6", @@ -1030,7 +1060,8 @@ "nodes_per_step": 276480, "steps": 1920000, "cost": 530841600000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "B12_cyl_block8", @@ -1063,7 +1094,8 @@ "nodes_per_step": 368640, "steps": 1920000, "cost": 707788800000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "B13_cyl_block12", @@ -1096,7 +1128,8 @@ "nodes_per_step": 552960, "steps": 1920000, "cost": 1061683200000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "B14_cyl_block16", @@ -1129,7 +1162,8 @@ "nodes_per_step": 737280, "steps": 1920000, "cost": 1415577600000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "B15_cyl_block24", @@ -1162,7 +1196,8 @@ "nodes_per_step": 1105920, "steps": 1920000, "cost": 2123366400000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "B16_cyl_block32", @@ -1195,7 +1230,8 @@ "nodes_per_step": 1474560, "steps": 1920000, "cost": 2831155200000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "C01_wall_hrr_re150", @@ -1244,7 +1280,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "C02_wall_hrr_re2000", @@ -1279,7 +1316,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "C03_wall_grad_re150", @@ -1328,7 +1366,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "C04_wall_grad_re2000", @@ -1363,7 +1402,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "C05_wall_bouzidi_re150", @@ -1412,7 +1452,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "C06_wall_bouzidi_re2000", @@ -1447,7 +1488,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "C07_wall_staircase_re150", @@ -1496,7 +1538,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "C08_wall_staircase_re2000", @@ -1531,7 +1574,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "C09_sub_hrr_00", @@ -1568,7 +1612,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "C10_sub_hrr_25", @@ -1605,7 +1650,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "C11_sub_hrr_50", @@ -1642,7 +1688,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "C12_sub_grad_00", @@ -1679,7 +1726,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "C13_sub_grad_25", @@ -1716,7 +1764,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "C14_sub_grad_50", @@ -1753,7 +1802,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "C15_sub_bouzidi_00", @@ -1790,7 +1840,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "C16_sub_bouzidi_25", @@ -1827,7 +1878,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "C17_sub_bouzidi_50", @@ -1864,7 +1916,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "C18_sub_staircase_00", @@ -1901,7 +1954,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "C19_sub_staircase_25", @@ -1938,7 +1992,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "C20_sub_staircase_50", @@ -1975,7 +2030,8 @@ "nodes_per_step": 61440, "steps": 38400, "cost": 2359296000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "D01_naca0012_a00", @@ -2026,7 +2082,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "D02_naca0012_a04", @@ -2077,7 +2134,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "D03_naca0012_a08", @@ -2128,7 +2186,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "D04_naca0012_a12", @@ -2179,7 +2238,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "D05_naca0012_a16", @@ -2230,7 +2290,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "D06_naca0012_re500", @@ -2281,7 +2342,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "D07_naca0012_re2000", @@ -2332,7 +2394,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "D08_naca0012_re10000", @@ -2383,7 +2446,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "D09_naca4412_a00", @@ -2434,7 +2498,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "D10_naca4412_a06", @@ -2485,7 +2550,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "D11_naca4412_a12", @@ -2536,7 +2602,8 @@ "nodes_per_step": 2097152, "steps": 2048000, "cost": 4294967296000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "D12_naca_chord48", @@ -2573,7 +2640,8 @@ "nodes_per_step": 294912, "steps": 576000, "cost": 169869312000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "D13_naca_chord96", @@ -2610,7 +2678,8 @@ "nodes_per_step": 1179648, "steps": 1152000, "cost": 1358954496000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "D14_naca_chord192", @@ -2647,7 +2716,8 @@ "nodes_per_step": 4718592, "steps": 2304000, "cost": 10871635968000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "E01_tandem_ld15", @@ -2690,7 +2760,8 @@ "nodes_per_step": 1036800, "steps": 1536000, "cost": 1592524800000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "E02_tandem_ld30", @@ -2733,7 +2804,8 @@ "nodes_per_step": 1036800, "steps": 1536000, "cost": 1592524800000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "E03_tandem_ld50", @@ -2776,7 +2848,8 @@ "nodes_per_step": 1036800, "steps": 1536000, "cost": 1592524800000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "E04_array_sparse", @@ -2819,7 +2892,8 @@ "nodes_per_step": 1036800, "steps": 576000, "cost": 597196800000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "E05_array_dense", @@ -2862,7 +2936,8 @@ "nodes_per_step": 1036800, "steps": 576000, "cost": 597196800000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "E06_perf_open20", @@ -2905,7 +2980,8 @@ "nodes_per_step": 720000, "steps": 800000, "cost": 576000000000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "E07_perf_open50", @@ -2948,7 +3024,8 @@ "nodes_per_step": 720000, "steps": 800000, "cost": 576000000000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "E08_multielem", @@ -2991,7 +3068,8 @@ "nodes_per_step": 2097152, "steps": 2400000, "cost": 5033164800000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "E09_thin_t05", @@ -3040,7 +3118,8 @@ "nodes_per_step": 720000, "steps": 1000000, "cost": 720000000000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "E10_thin_t025", @@ -3089,7 +3168,8 @@ "nodes_per_step": 720000, "steps": 1000000, "cost": 720000000000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "E11_wedge", @@ -3135,7 +3215,8 @@ "nodes_per_step": 720000, "steps": 1200000, "cost": 864000000000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "E12_serrated", @@ -3181,7 +3262,8 @@ "nodes_per_step": 720000, "steps": 1200000, "cost": 864000000000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "F01_inlet2d", @@ -3214,7 +3296,8 @@ "nodes_per_step": 608256, "steps": 1152000, "cost": 700710912000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "F02_inlet6d", @@ -3247,7 +3330,8 @@ "nodes_per_step": 718848, "steps": 1152000, "cost": 828112896000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "F03_inlet16d", @@ -3280,7 +3364,8 @@ "nodes_per_step": 995328, "steps": 1152000, "cost": 1146617856000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "F04_outlet5d", @@ -3313,7 +3398,8 @@ "nodes_per_step": 304128, "steps": 1152000, "cost": 350355456000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "F05_outlet15d", @@ -3346,7 +3432,8 @@ "nodes_per_step": 580608, "steps": 1152000, "cost": 668860416000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "F06_outlet40d", @@ -3379,7 +3466,8 @@ "nodes_per_step": 1271808, "steps": 1152000, "cost": 1465122816000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "F07_refine1", @@ -3412,7 +3500,8 @@ "nodes_per_step": 245760, "steps": 768000, "cost": 188743680000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "F08_refine2", @@ -3445,7 +3534,8 @@ "nodes_per_step": 501218, "steps": 768000, "cost": 384935424000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "F09_refine3", @@ -3478,7 +3568,8 @@ "nodes_per_step": 1106235, "steps": 768000, "cost": 849588480000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "G01_xt_re150_uniform", @@ -3535,7 +3626,8 @@ "cost": 318504960000, "outputs": [ "xt" - ] + ], + "shard": 2 }, { "id": "G02_xt_re150_rest", @@ -3592,7 +3684,8 @@ "cost": 318504960000, "outputs": [ "xt" - ] + ], + "shard": 3 }, { "id": "G03_xt_re2000_uniform", @@ -3649,7 +3742,8 @@ "cost": 318504960000, "outputs": [ "xt" - ] + ], + "shard": 4 }, { "id": "G04_xt_re2000_rest", @@ -3706,7 +3800,8 @@ "cost": 318504960000, "outputs": [ "xt" - ] + ], + "shard": 2 }, { "id": "G05_xt_re20000_uniform", @@ -3763,7 +3858,8 @@ "cost": 318504960000, "outputs": [ "xt" - ] + ], + "shard": 1 }, { "id": "G06_xt_re20000_rest", @@ -3820,7 +3916,8 @@ "cost": 318504960000, "outputs": [ "xt" - ] + ], + "shard": 5 }, { "id": "G07_sponge0", @@ -3855,7 +3952,8 @@ "nodes_per_step": 552960, "steps": 768000, "cost": 424673280000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "G08_sponge40", @@ -3890,7 +3988,8 @@ "nodes_per_step": 552960, "steps": 768000, "cost": 424673280000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "G09_spongein0", @@ -3925,7 +4024,8 @@ "nodes_per_step": 552960, "steps": 768000, "cost": 424673280000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "G10_spongein40", @@ -3960,7 +4060,8 @@ "nodes_per_step": 552960, "steps": 768000, "cost": 424673280000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "G11_limit_re10000", @@ -3991,7 +4092,8 @@ "nodes_per_step": 552960, "steps": 384000, "cost": 212336640000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "G12_limit_re50000", @@ -4022,7 +4124,8 @@ "nodes_per_step": 552960, "steps": 384000, "cost": 212336640000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "G13_limit_re200000", @@ -4053,7 +4156,8 @@ "nodes_per_step": 552960, "steps": 384000, "cost": 212336640000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "G14_lifetime", @@ -4100,7 +4204,8 @@ "nodes_per_step": 552960, "steps": 10000000, "cost": 5529600000000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "H01_sym_cyl", @@ -4135,7 +4240,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "H02_sym_foil", @@ -4174,7 +4280,8 @@ "nodes_per_step": 524288, "steps": 768000, "cost": 402653184000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "H03_mirror_plus", @@ -4211,7 +4318,8 @@ "nodes_per_step": 524288, "steps": 768000, "cost": 402653184000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "H04_mirror_minus", @@ -4248,7 +4356,8 @@ "nodes_per_step": 524288, "steps": 768000, "cost": 402653184000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "H05_mach02", @@ -4283,7 +4392,8 @@ "nodes_per_step": 245760, "steps": 1280000, "cost": 314572800000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "H06_mach05", @@ -4318,7 +4428,8 @@ "nodes_per_step": 245760, "steps": 512000, "cost": 125829120000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "H07_mach10", @@ -4351,7 +4462,8 @@ "nodes_per_step": 245760, "steps": 256000, "cost": 62914560000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "H08_prec_cpu", @@ -4384,7 +4496,8 @@ "nodes_per_step": 245760, "steps": 1024000, "cost": 251658240000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "H09_prec_gpu", @@ -4417,7 +4530,8 @@ "nodes_per_step": 245760, "steps": 1024000, "cost": 251658240000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "I01_fine_cylinder", @@ -4464,7 +4578,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "I02_fine_square", @@ -4511,7 +4626,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "I03_fine_diamond", @@ -4558,7 +4674,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "I04_fine_ellipse", @@ -4607,7 +4724,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 4 }, { "id": "I05_fine_naca", @@ -4658,7 +4776,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 5 }, { "id": "I06_fine_triangle", @@ -4705,7 +4824,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 1 }, { "id": "I07_fine_plate", @@ -4756,7 +4876,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 2 }, { "id": "I08_fine_wedge", @@ -4804,7 +4925,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 3 }, { "id": "I09_fine_multi", @@ -4847,7 +4969,8 @@ "nodes_per_step": 8388608, "steps": 3072000, "cost": 25769803776000, - "outputs": [] + "outputs": [], + "shard": 4 } ] } \ No newline at end of file diff --git a/docs/theory/2d_solver/docker-compose.server.yml b/docs/theory/2d_solver/docker-compose.server.yml index c4ee1f8..6522d1a 100644 --- a/docs/theory/2d_solver/docker-compose.server.yml +++ b/docs/theory/2d_solver/docker-compose.server.yml @@ -22,7 +22,7 @@ name: kbc2d # ── общая часть всех сервисов ──────────────────────────────────────────────── x-kbc2d: &kbc2d - image: notbigghost/kbc2d:1.2.0 + image: notbigghost/kbc2d:1.3.0 pull_policy: missing volumes: - ./out:/work/bench/out diff --git a/docs/theory/2d_solver/docker-compose.shards.yml b/docs/theory/2d_solver/docker-compose.shards.yml new file mode 100644 index 0000000..f8835ad --- /dev/null +++ b/docs/theory/2d_solver/docker-compose.shards.yml @@ -0,0 +1,77 @@ +# Кампания, разделённая на ПЯТЬ равных по времени долей — по одной на машину. +# +# Рассчитан на чужой ПК с видеокартой под Windows (Docker Desktop) или WSL2. Файл +# САМОДОСТАТОЧЕН: тянет готовый образ из реестра, исходники не нужны. На машину переносятся +# два файла — этот и shard.bat — и запускается одна команда: +# +# shard.bat 3 # Windows, двойной клик не годится: нужен номер +# docker compose -f docker-compose.shards.yml up -d shard3 # то же вручную, из любой оболочки +# docker compose -f docker-compose.shards.yml logs -f shard3 # смотреть ход +# +# Контейнер стартует и сразу считает: сам проверяет, видна ли карта, сверяет её с CPU-эталоном +# (parity.py, ~2 мин) и идёт по своей доле. Если что-то не так — останавливается с объяснением. +# +# Что ДОЛЖНО стоять на машине (в контейнер это положить нельзя): +# * драйвер видеокарты под Windows — Vulkan внутри контейнера транслируется в D3D12 (dzn); +# * Docker Desktop с бэкендом WSL2 (по умолчанию так и есть) либо Docker внутри WSL2. +# +# Доли посчитаны так, чтобы на ОДИНАКОВЫХ картах закончиться одновременно (≈24 ч каждая при +# 1200 MLUPS, с поправкой на размер сетки — см. bench/gen_scenarios.py). На разных картах +# закончатся в разное время. Результаты — в ./out рядом с этим файлом; собрать их с пяти +# машин = скопировать все out/ в одну папку (каталоги прогонов не пересекаются, у каждой доли +# своя сводка summary_shardN.csv). +# +# Перезапуск безопасен: --resume пропускает всё, у чего уже есть summary.json. + +name: kbc2d + +x-kbc2d: &kbc2d + image: notbigghost/kbc2d:1.3.0 + # Если образа нет ни локально, ни в реестре — `docker compose -f docker-compose.shards.yml + # build` соберёт его из каталога с этим файлом (нужны исходники). + build: + context: . + args: + VERSION: "1.3.0" + pull_policy: missing + devices: + # сама видеокарта (WDDM); есть в любом WSL2, в том числе внутри Docker Desktop + - /dev/dxg:/dev/dxg + volumes: + - ./out:/work/bench/out + # libd3d12.so и libdxcore.so, которые нужны dzn; каталог наполняет сам WSL + - /usr/lib/wsl:/usr/lib/wsl:ro + # Доля задаётся переменной KBC2D_SHARD у каждого сервиса. Команда указана явно только затем, + # чтобы не унаследовать от образа CMD --dry-run. + command: ["--resume"] + # on-failure, а НЕ unless-stopped: доля завершается штатно с кодом 0, и «перезапускать + # всегда» гоняло бы контейнер по кругу. Падение (OOM, сбой драйвера) будет подхвачено. + restart: on-failure:5 + stop_grace_period: 30s + logging: + driver: json-file + options: + max-size: "50m" + max-file: "5" + +services: + shard1: + <<: *kbc2d + container_name: kbc2d-shard1 + environment: { KBC2D_SHARD: "1" } + shard2: + <<: *kbc2d + container_name: kbc2d-shard2 + environment: { KBC2D_SHARD: "2" } + shard3: + <<: *kbc2d + container_name: kbc2d-shard3 + environment: { KBC2D_SHARD: "3" } + shard4: + <<: *kbc2d + container_name: kbc2d-shard4 + environment: { KBC2D_SHARD: "4" } + shard5: + <<: *kbc2d + container_name: kbc2d-shard5 + environment: { KBC2D_SHARD: "5" } diff --git a/docs/theory/2d_solver/docker-compose.wsl.yml b/docs/theory/2d_solver/docker-compose.wsl.yml index 1ca5ba3..b38f563 100644 --- a/docs/theory/2d_solver/docker-compose.wsl.yml +++ b/docs/theory/2d_solver/docker-compose.wsl.yml @@ -32,14 +32,14 @@ name: kbc2d # ── общая часть всех сервисов ──────────────────────────────────────────────── x-kbc2d: &kbc2d - image: notbigghost/kbc2d:1.2.0 + image: notbigghost/kbc2d:1.3.0 # Контекст сборки — каталог с этим файлом. Если образа нет ни локально, ни в реестре, # достаточно `docker compose -f docker-compose.wsl.yml build`: доступ к Docker Hub # для запуска не обязателен. build: context: . args: - VERSION: "1.2.0" + VERSION: "1.3.0" pull_policy: missing devices: - /dev/dxg:/dev/dxg diff --git a/docs/theory/2d_solver/shard.bat b/docs/theory/2d_solver/shard.bat new file mode 100644 index 0000000..03740bf --- /dev/null +++ b/docs/theory/2d_solver/shard.bat @@ -0,0 +1,39 @@ +@echo off +rem Запуск одной доли кампании kbc2d на этой машине: shard.bat 3 +rem Нужны: драйвер видеокарты и Docker Desktop (бэкенд WSL2). Рядом должен лежать +rem docker-compose.shards.yml. Результаты появятся в папке out рядом с этим файлом. +chcp 65001 >nul +setlocal +cd /d "%~dp0" + +set "N=%~1" +if "%N%"=="" goto usage +if "%N%"=="1" goto ok +if "%N%"=="2" goto ok +if "%N%"=="3" goto ok +if "%N%"=="4" goto ok +if "%N%"=="5" goto ok +:usage +echo Использование: shard.bat ^<номер доли 1..5^> +echo shard.bat 3 поднять долю 3 и смотреть её журнал +echo Остановить: docker compose -f docker-compose.shards.yml stop +exit /b 2 + +:ok +if not exist docker-compose.shards.yml ( + echo Рядом с shard.bat нет docker-compose.shards.yml. + exit /b 1 +) +docker info >nul 2>&1 +if errorlevel 1 ( + echo Docker не отвечает. Запустите Docker Desktop, дождитесь зелёного статуса и повторите. + exit /b 1 +) + +docker compose -f docker-compose.shards.yml up -d shard%N% +if errorlevel 1 exit /b 1 +echo. +echo Доля %N% запущена и считает в фоне. Журнал ниже; Ctrl+C закрывает только журнал, +echo счёт продолжается. Результаты: %CD%\out +echo. +docker compose -f docker-compose.shards.yml logs -f shard%N%