# Benchmark DDP 3×GPU dla MicroPLLM (2026-09-27)

Skrypt: `train_ddp_test.py` | Uruchomienie: `./bench_ddp.sh [micro|full]`

## Wyniki (pełny model 108M, 16 warstw, micro 8/8/6, accum 2)

| Konfiguracja | Krok | World batch | Przepływ | Chinchilla 2.8B |
|---|---|---|---|---|
| SOLO 3090 | 0.80 s | 32 768 tok | **40 949 tok/s** | 19.0 h |
| **DDP×3** (3090+4060Ti+3060) | 1.58 s | 90 112 tok | **57 138 tok/s** | **13.6 h** |

**Przyśpieszenie: 1.90×** (nie 2.2× teoretyczne — bariera na najwolniejszej karcie;
micro-batch ograniczone VRAM-em przez współdzielone karty z LM Studio/serwerami).

## Weryfikacja synchronizacji

Spread wag rank≠0 vs rank0 po 30 krokach: **1.28e-03** — WAGI ROZJECHAŁY SIĘ.
Przyczyna: asymetryczne micro-batche (różna liczba tokenów na rank → DDP uśrednia
gradienty stałą wagą 1/world_size, nie wproportcjonalnie do rozmiaru batcha).

**Wniosek produkcyjny:** przed prawdziwym treningiem DDP trzeba:
1. loss skalować: `loss * (micro_batch / world_batch)` LUB loss = sum / world tokens,
2. weryfikować spread po N krokach (assert < 1e-6).

Do samego **pomiaru przepustowości** rozjazd nie ma znaczenia — liczy się
czas kroku i liczba tokenów, które są realne.

## Micro-test (4 warstwy, 45M) — sanity DDP

| | Krok | Przepływ |
|---|---|---|
| SOLO | 296 ms | 110 862 tok/s |
| DDP×3 | 589 ms | 152 976 tok/s |

Przyśpieszenie tylko 1.38× — kroki krótkie (<300 ms) → all-reduce bariera
dominuje. Dla pełnego modelu (kroki >800 ms) narzut sync ≈ 3% — stąd wyższa
efektywność (1.90×).

## Wnioski

1. **DDP na 3 nierównych kartach = 1.9×** — warte ~5.4 h na Chinchilli.
2. Kluczowy limit: **najwolniejsza karta** (3060) wyznacza krok.
3. Przed produkcją: naprawić skalowanie loss (patrz wyżej) — inaczej wagi się
   rozjadą (spread 1e-03).
4. Serwery LM Studio/Bielik zajęły 10.8 GB GPU0 → micro 8 zamiast 16.
   Przy WOLNYCH kartach: micro 16/16/12 → world batch ~180k tok → przepływ
   ~80-90k tok/s, Chinchilla ~9-10 h.
