@@ -404,7 +404,65 @@ jobs:
404404 "$1" "$2" "$3" "$4" "$5" "$6" "$i" "$7"
405405 done
406406 }
407- if [ "$full" = 1 ]; then ln=3; mn=1; wn=2; else ln=1; mn=1; wn=1; fi
407+ # Shard count follows the WORK, per platform, measured.
408+ #
409+ # It used to be binary — full run: linux 3 / macos 1 / windows 2,
410+ # anything else: 1 each — which asserts two things that are not
411+ # true. "A partial run is small": touching a widely consumed
412+ # descriptor selects every member that consumes it, and this PR's
413+ # `pkgs/c/compat.openssl.lua` selected four; one linux shard took
414+ # grpc-codegen (3563s) and grpc-module (1701s) back to back and was
415+ # cancelled at exactly 1h30m, the job cap. "A full macOS run fits in
416+ # one shard": at 6922s measured it does not — it fit only while the
417+ # total sat just under the cap, and the run that added grpc-codegen
418+ # (1715s on macOS) pushed it to 1h30m20s.
419+ #
420+ # Sharding is not only a wall-clock lever. Each shard is its own job
421+ # with its own `timeout-minutes`, so it is also how the work is made
422+ # to FIT. That is the half the "macOS concurrency is 1, so extra
423+ # shards run back to back" note above left out: back to back is fine
424+ # when the alternative is not finishing.
425+ #
426+ # tests/member-timings.tsv already holds every member's measured
427+ # cost and plan_shards.lua already packs by it (LPT), so the fan-out
428+ # comes from the same table: sum this run's members for that
429+ # platform and take one shard per ~70 minutes, which leaves ~20
430+ # minutes of headroom under the 90-minute cap for a cold cache.
431+ #
432+ # The caps are where runner concurrency comes back in: linux 3 (the
433+ # measured concurrency — a 4th shard would queue), macOS 2, windows
434+ # 2. Past those, more shards buy fit that is already there and pay
435+ # another checkout + mcpp download + cache restore.
436+ #
437+ # Full run, from the table: linux 13570s over 3 -> ~75min/shard
438+ # (observed slowest 77), macOS 6922s over 2 -> ~57, windows 8043s
439+ # over 2 -> ~67. linux is the tight one — its cap binds before the
440+ # ~70-minute target does, so it is the first place to look if a
441+ # cold full run starts brushing 90 again. The levers, in order:
442+ # raise the linux cap to 4 (costs a queued runner), then the job
443+ # timeout.
444+ shards_for() { # platform cap -> shard count
445+ local secs
446+ secs=$(XPLAT="$1" lua5.4 -e '
447+ local plat = os.getenv("XPLAT")
448+ local sel, all = {}, (os.getenv("MEMBERS") == "__ALL__")
449+ if not all then
450+ for m in (os.getenv("MEMBERS") or ""):gmatch("%S+") do sel[m] = true end
451+ end
452+ local total = 0
453+ for line in io.lines("tests/member-timings.tsv") do
454+ local p, m, s = line:match("^(%S+)\t(%S+)\t(%d+)$")
455+ if p == plat and m and (all or sel[m]) then total = total + tonumber(s) end
456+ end
457+ print(total)')
458+ local n=$(( secs / 4200 + 1 ))
459+ [ "$n" -gt "$2" ] && n="$2"
460+ echo "$1 work: ${secs}s (measured) -> $n shard(s)" >&2
461+ echo "$n"
462+ }
463+ ln=$(shards_for linux 3)
464+ mn=$(shards_for macos 2)
465+ wn=$(shards_for windows 2)
408466 {
409467 printf '{"include":['
410468 emit linux ubuntu-latest linux-x86_64 tar.gz bin/mcpp registry/bin/xlings "$ln"
0 commit comments