app: a named DFlash2 with a number of requests passes Expert mode's batch-mtp wish on as in 0.2.10, so the Metal fallback to the MTP keeps its --batch-mtp

The server drops --batch-mtp when DFlash2 runs and keeps it when the MTP runs; a test pins the Metal fallback arguments equal to the MTP's.
This commit is contained in:
Niko1221 committed 2026-11-03 17:52:57 +01:00
1 parent ae5e73de20
commit 181b668e5a
3 files changed
+21 -8

No files matched your search

+4 -4
View File
@@ -112,10 +112,10 @@ export function chooseParallel({ config = {}, values = {}, hardware = null, requ
// A number someone chose (including 1) is the person's decision, and so is an explicit --batch in the engine arguments.
if (facts.explicitBatch || (chosen !== null && Number.isFinite(chosen))) {
const slots = facts.explicitBatch ? null : Math.max(1, Math.min(1024, Math.trunc(chosen)));
// DFlash2 chosen by name with a number of requests (owner, 2026-11-03: the person's own choice wins): the engine runs DFlash2 with that many requests, a drafter per request
// (strata_control/drafting.py blocked_by `named`), so the MTP's --batch-mtp is not added beside it. Auto that resolved to DFlash2 is not named: it keeps the MTP for several requests.
const named = (values.drafting ?? config.drafting) === 'dflash2' && (drafter ?? 'dflash2') === 'dflash2';
const wantMtp = !named && (values.batchMtp ?? config.batchMtp) === true && !facts.batchMtp && facts.mtp && facts.gpus.length === 1 && (slots ?? 0) > 1;
// DFlash2 chosen by name with a number of requests (owner, 2026-11-03: the person's own choice wins) runs DFlash2 with that many requests, a drafter per request
// (strata_control/drafting.py blocked_by `named`). Expert mode's batch-mtp wish is still added here as in 0.2.10: the server knows the backend and the engine, takes
// --batch-mtp out when DFlash2 runs, and keeps it when the MTP runs instead (Metal, which has no per-request drafters).
const wantMtp = (values.batchMtp ?? config.batchMtp) === true && !facts.batchMtp && facts.mtp && facts.gpus.length === 1 && (slots ?? 0) > 1;
return { slots: slots ?? 0, batchMtp: wantMtp, explicit: true, requested, note: null, slotGb: slot };
}
// DFlash2 (named, or Auto where the engine has it) and nobody chose a number of requests: one at a time, the app does not fill in slots beside it. (A number the person chose is kept
+4 -4
View File
@@ -197,21 +197,21 @@ test('DFlash2 named with a number of requests the person chose: that many, no no
const big = hw(72);
for (const n of [2, 4, 8]) {
const viaValues = chooseParallel({ config: cfg(32768), values: { drafting: 'dflash2', parallel: n }, hardware: big });
assert.deepEqual([viaValues.slots, viaValues.explicit, viaValues.note, viaValues.batchMtp], [n, true, null, false], `values ${n}`);
assert.deepEqual([viaValues.slots, viaValues.explicit, viaValues.note], [n, true, null], `values ${n}`);
const viaConfig = chooseParallel({ config: cfg(32768, { drafting: 'dflash2', parallel: n }), hardware: big });
assert.deepEqual([viaConfig.slots, viaConfig.explicit, viaConfig.note], [n, true, null], `saved ${n}`);
const applied = applyParallel(cfg(32768, { drafting: 'dflash2', parallel: n }), viaConfig);
assert.equal(applied.cfg.parallel, n, 'the number stays');
assert.equal(applied.note, null);
assert.ok(!applied.cfg.args.includes('--batch-mtp'), 'the MTP slot switch is not added beside DFlash2');
assert.ok(!applied.cfg.args.includes('--batch-mtp'), 'no wish, no --batch-mtp');
}
// the same through the resolved drafter the load passes, and a --batch in the engine arguments
assert.equal(chooseParallel({ config: cfg(32768, { drafting: 'dflash2', parallel: 4 }), drafter: 'dflash2', hardware: big }).slots, 4);
const withBatch = chooseParallel({ config: { ...cfg(32768, { drafting: 'dflash2' }), args: ['--max-context', '32768', '--mtp', '/m', '--batch', '3'] }, drafter: 'dflash2', hardware: big });
assert.deepEqual([withBatch.explicit, withBatch.note], [true, null]);
// Expert mode's batch-mtp wish is the MTP's: DFlash2 named does not take it, the MTP and Auto do as before
// Expert mode's batch-mtp wish is passed on exactly as in 0.2.10 for every drafter: the server drops --batch-mtp when DFlash2 runs and keeps it when the MTP runs (Metal)
const wish = (extra, drafter) => chooseParallel({ config: cfg(32768), values: { parallel: 4, batchMtp: true, ...extra }, drafter, hardware: big }).batchMtp;
assert.equal(wish({ drafting: 'dflash2' }, 'dflash2'), false);
assert.equal(wish({ drafting: 'dflash2' }, 'dflash2'), true);
assert.equal(wish({ drafting: 'mtp' }, 'mtp'), true);
assert.equal(wish({}, 'dflash2'), true, 'Auto that resolved to DFlash2 is not named: the MTP serves the several requests');
assert.equal(wish({ drafting: 'dflash2' }, 'mtp'), true, 'named, but the drafter is not here yet: the MTP runs and keeps its slot switch');
+13
View File
@@ -241,6 +241,19 @@ class TheServerAndTheTerminalEndAtTheSameArguments(Base):
self.assertIn("--layer-split", args)
self.assertNotIn("--mtp", args)
def test_metal_named_dflash2_with_requests_starts_the_mtp_exactly_as_0_2_10_did(self):
"""Metal has no per-request drafters, so a DFlash2 chosen by name with several requests is the MTP there, with the MTP's own --batch-mtp (the saved one, or Expert mode's
wish, which the app adds to the arguments) kept: the same arguments the MTP chosen by name gets, which is what 0.2.10 started for this case."""
for parallel in (2, 4, 8):
named = self.server_args(self.cfg(drafting="dflash2", parallel=parallel), "metal", ())
self.assertEqual(named, self.server_args(self.cfg(drafting="mtp", parallel=parallel), "metal", ()), parallel)
self.assertEqual(named, self.server_args(self.cfg(parallel=parallel), "metal", ()), "and the same as Auto")
self.assertIn("--batch-mtp", named)
self.assertEqual((flag(named, "--batch"), flag(named, "--mtp"), "--draft" in named), (str(parallel), str(self.data / "mtp" / "rt"), False))
# the same saved arguments on CUDA: DFlash2 with the requests, the MTP's slot switch is taken out
cuda = self.server_args(self.cfg(drafting="dflash2", parallel=4))
self.assertEqual((loaded(cuda), "--batch-mtp" in cuda, flag(cuda, "--batch")), ({"dflash2"}, False, "4"))
def test_the_all_cards_split_engine_still_runs_its_mtp(self):
from tests.split import test_split_engine as TS
(Path(self.tmp.name) / "data").mkdir(exist_ok=True)