layer split auto (CUDA): a stage's link scales its miss cost only against the fastest stage's link and from a 4x gap on (#2007)

0.1.41 (0391e478) scaled each stage's miss term by 20 GB/s / its probed link, for 2x 4090 D
with CUDA1 on a physical x1 link (1.6 GB/s: x12, K 22 -> 38, prompt ~350 -> ~1400 tok/s).
On 2x Tesla T10 the same rule moved auto from K=23 to K=14: CUDA1 runs 34 of 48 layers, and as
the prompt path is a pipeline the slower stage sets the rate - 256K prompt 1035 -> 795 tok/s,
decode 46.8 -> 39.5; --layer-split 23 on 0.1.43 restores both (xiake-1 in #2007).

split_rules::link_miss_scale: the scale is the fastest stage's link over this stage's, applied
only from a 4x gap (a riser or chipset x1/x4 slot beside an x16 one), capped at 64. A symmetric
rig keeps the fitted formula whatever its link speed; the x1 case still gets ~x15.
STRATA_SPLIT_LINK_ABS=1 restores the 0.1.41 rule. SYCL has no link term (unchanged).
Test: split_rules_test (the x1 case, equal gen3 cards, a 2x gap, caps, unprobed stages).
Not run on the reporter's T10s: the reply asks for the 'link ... -> miss cost' lines.
This commit is contained in:
Niko1221 committed 2026-10-13 05:25:31 +02:00
1 parent 640ac438be
commit 9d41e18bd9
3 files changed
+50 -6

No files matched your search

+23
View File
@@ -74,6 +74,29 @@ inline size_t pick_with_headroom(const std::vector<Placement>& c, double tol) {
return pick;
}
// ---- #2007: the miss cost of a stage on a narrower link. 0.1.41 scaled each stage's miss term by 20 GB/s / its probed
// link (clamped to 1..64), for 2x 4090 D with CUDA1 on a physical x1 link (1.6 GB/s: x12, auto K 22 -> 38, prompt
// ~350 -> ~1400 tok/s). The same scale moved 2x Tesla T10 from K=23 to K=14: prompt -23%, decode -15% (xiake-1).
// So the scale is now relative to the stage with the fastest link (a symmetric rig keeps the fitted formula, whatever
// its link speed) and applies only from kLinkScaleMin on (a narrow riser or a chipset x1/x4 slot against an x16 one);
// below that the probe's noise and the formula's fit are the larger effects.
constexpr double kLinkScaleMin = 4.0;
/// Per stage: the factor on its miss term, from the probed H2D GB/s of each stage (<= 0: not probed -> 1.0).
inline std::vector<double> link_miss_scale(const std::vector<double>& gbps, double min_ratio = kLinkScaleMin) {
double fastest = 0.0;
for (const double b : gbps) fastest = b > fastest ? b : fastest;
std::vector<double> s(gbps.size(), 1.0);
if (fastest <= 0.0) return s;
for (size_t i = 0; i < gbps.size(); ++i) {
if (gbps[i] <= 0.0) continue;
const double r = fastest / gbps[i];
s[i] = r >= min_ratio ? (r > 64.0 ? 64.0 : r) : 1.0;
}
return s;
}
/// The smallest spare room over the stages of `cuts`: room[i] - session(lb, le) - need(lb, le), where `need_prefix[l]`
/// is the bytes of every expert of layers [0, l) (n_layers + 1 entries).
template <class Session>
+11 -6
View File
@@ -3761,17 +3761,22 @@ int main(int argc, char** argv) {
}
// The per-stage link, measured here (the stage-setup probes are skipped when --pcie-frac is given, and the
// search needs the reading either way).
std::vector<double> link_scale((size_t) ns, 1.0);
std::vector<double> link_gbps((size_t) ns, -1.0);
for (int i = 0; i < ns; ++i) {
const int dev = i == 0 ? 0 : stages[(size_t) i - 1]->dev;
const strata::core::OnDevice on(dev);
std::string bursts;
const double bw = native_pack ? probe_pcie_h2d_gbps(&bursts) : -1.0;
// Never below 1.0: a link at or above the 20 GB/s reference keeps the fitted cost exactly (a x16
// gen4/5 reads 26-28 and must not credit misses below the formula the sweep's K was fitted with).
if (bw > 0.0) link_scale[(size_t) i] = std::clamp(20.0 / bw, 1.0, 64.0);
link_gbps[(size_t) i] = native_pack ? probe_pcie_h2d_gbps(&bursts) : -1.0;
}
// #2007: relative to the fastest stage's link and only from a 4x gap on (split_rules::link_miss_scale): a
// symmetric rig, or a moderate gap, keeps the fitted formula. STRATA_SPLIT_LINK_ABS=1: 0.1.41's 20 GB/s rule.
static const bool link_abs = [] { const char* v = std::getenv("STRATA_SPLIT_LINK_ABS"); return v && v[0] == '1'; }();
std::vector<double> link_scale = strata::program::split_rules::link_miss_scale(link_gbps);
for (int i = 0; i < ns; ++i) {
const double bw = link_gbps[(size_t) i];
if (link_abs) link_scale[(size_t) i] = bw > 0.0 ? std::clamp(20.0 / bw, 1.0, 64.0) : 1.0;
std::fprintf(stderr, "strata generate: layer split auto: CUDA%d link %.1f GB/s -> miss cost x%.2f\n",
dev, bw, link_scale[(size_t) i]);
i == 0 ? 0 : stages[(size_t) i - 1]->dev, bw, link_scale[(size_t) i]);
}
const double miss_ms = std::getenv("STRATA_SPLIT_MISS_MS") ? std::atof(std::getenv("STRATA_SPLIT_MISS_MS")) : 190.0;
// ---- THE COVERAGE CURVE: HOW MUCH ROUTED MASS A CACHE HOLDS, AND WHY IT IS NO LONGER A POWER LAW.
+16
View File
@@ -75,6 +75,22 @@ int main() {
CHECK(pick_with_headroom(same, 0.0) == 0);
CHECK(pick_with_headroom({}, 0.1) == 0);
}
// #2007: the miss scale per link
{
// the case 0.1.41's scale was made for: CUDA1 on a physical x1 link beside an x16 one
const std::vector<double> x1 = link_miss_scale({24.0, 1.6});
CHECK(x1[0] == 1.0 && x1[1] > 14.9 && x1[1] < 15.1);
// two equal cards on gen3 x16 (2x Tesla T10, P100s): the fitted formula, whatever the link speed
const std::vector<double> eq = link_miss_scale({12.0, 12.0});
CHECK(eq[0] == 1.0 && eq[1] == 1.0);
// a moderate gap (x8 beside x16, or the probe's noise): no scale
const std::vector<double> mod = link_miss_scale({11.4, 5.9});
CHECK(mod[0] == 1.0 && mod[1] == 1.0);
// a 4x gap and more scales by the ratio, capped at 64; unprobed stages stay 1
const std::vector<double> big = link_miss_scale({26.0, 6.0, 0.2, -1.0});
CHECK(big[0] == 1.0 && big[1] > 4.3 && big[1] < 4.4 && big[2] == 64.0 && big[3] == 1.0);
CHECK(link_miss_scale({-1.0, -1.0})[1] == 1.0);
}
if (failed == 0) std::printf("split_rules_test: ok\n");
return failed ? 1 : 0;
}