fix: bound test shard size independently of concurrency

Remove the 32-shard cap so growing inventories do not overfill fixed timeout windows. Keep serial Runtime/Worker/Server shards at most 36 cases and default top-level concurrency at most eight, with explicit --jobs overrides retained. No test exclusions or timeout increases.

Validated the complete Server inventory through the normal runner helpers: 1724 passed, 4 existing ignored, no failures or timeouts; 50 suites including doctests, 580 seconds execution. Runner and naming checks: 26 passed. Root cargo check and formatting/diff checks passed.
This commit is contained in:
2026-11-01 01:54:34 +09:00
parent 922e5e3fc3
commit d0f22d871a
3 changed files with 18 additions and 13 deletions
+1 -1
View File
@@ -53,7 +53,7 @@
### runner:選択の帳簿と実行引数を照合する
`tools/test.test.ts` の `round-robin shards retain every listed name exactly once at thresholds and the 32-shard cap` は本番parser/sharderへ実形式のlistingを入力し、全名の一意分配と `task.args.slice(3) === selectedNames`、exact/thread/ignore flagsをassertする。`runtime listing persists complete name inventory for large and small binaries` はDeno子でlibtest listingを代替し、本番discovery/executeの保存inventoryを再読取りする。実Rust libtest全体の実行結果照合ではない。
`tools/test.test.ts` の `round-robin shards retain every listed name without exceeding the case budget` は本番parser/sharderへ実形式のlistingを入力し、全名の一意分配、分割後のケース数上限と `task.args.slice(3) === selectedNames`、exact/thread/ignore flagsをassertする。`runtime listing persists complete name inventory for large and small binaries` はDeno子でlibtest listingを代替し、本番discovery/executeの保存inventoryを再読取りする。実Rust libtest全体の実行結果照合ではない。
`execute preserves live stdout/stderr and times out a group containing a grandchild`、`execute escalates SIGTERM to SIGKILL and reaps a stubborn direct child`、`parent SIGINT/SIGTERM cleans up active groups, reaps children and does not spawn queued commands` は実隔離子プロセスを起動し、PID消滅・保存result・非起動のqueued PIDを観測する。fixtureに独立watchdogがあり、finallyでも回収する。同process group外へ自ら離脱した子孫は対象外。局所入力表を重いrunner全体起動へ移さない。
+9 -7
View File
@@ -106,9 +106,9 @@ function assertThrows(fn: () => unknown) {
assert(failed, "expected failure");
}
Deno.test("CPU-derived jobs accommodates concurrent suites within the CLI bound", () => {
assert(defaultJobs(24) === 32);
assert(defaultJobs(128) === 32);
Deno.test("default jobs bound suite pressure independently of explicit CLI concurrency", () => {
assert(defaultJobs(24) === 8);
assert(defaultJobs(128) === 8);
assert(defaultJobs(6) === 8);
assert(defaultJobs(1) === 2);
assert(parseJobs([]) === defaultJobs());
@@ -153,7 +153,7 @@ function listedNames(count: number) {
return Array.from({ length: count }, (_, i) => `unit::case_${i}`);
}
Deno.test("round-robin shards retain every listed name exactly once at thresholds and the 32-shard cap", () => {
Deno.test("round-robin shards retain every listed name without exceeding the case budget", () => {
const task = {
name: "pkg/binary",
command: "/test-binary",
@@ -178,9 +178,10 @@ Deno.test("round-robin shards retain every listed name exactly once at threshold
"small binaries must be unchanged",
);
} else {
const expected = Math.min(32, Math.ceil(count / 36));
const expected = Math.ceil(count / 36);
assert(shards.length === expected);
const lengths = shards.map((shard) => shard.selectedNames.length);
assert(Math.max(...lengths) <= 36);
assert(Math.max(...lengths) - Math.min(...lengths) <= 1);
shards.forEach((shard, index) => {
assert(
@@ -212,7 +213,7 @@ Deno.test("global runtime-path packages serialize every normal target without lo
args: [],
cwd: "/pkg",
};
for (const count of [0, 1, 59, 72, 73, 1135]) {
for (const count of [0, 1, 36, 37, 59, 72, 73, 1135, 1716, 2000]) {
const names = listedNames(count);
const shards = shardRustCommand(task, names);
assert(
@@ -222,7 +223,8 @@ Deno.test("global runtime-path packages serialize every normal target without lo
for (const shard of shards) {
const args = shard.task.args;
assert(args[args.indexOf("--test-threads") + 1] === "1");
if (count > 72) {
assert(shard.selectedNames.length <= 36);
if (count > 36) {
assert(args[0] === "--exact");
assert(args.slice(3).join() === shard.selectedNames.join());
} else {
+8 -5
View File
@@ -12,9 +12,10 @@ export const BUILD_TIMEOUT_MS = 1_800_000;
export const MAX_JOBS = 64;
export function defaultJobs(cpus = availableParallelism()): number {
// Leave headroom for internal runners; higher top-level counts can be chosen
// explicitly, but are not assumed to improve throughput or timing stability.
return Math.min(32, Math.max(1, Math.ceil(cpus * 4 / 3)));
// Each suite can spawn its own Runtime, database executors and compiler work.
// CPU count alone over-admits these suites and consumes their timeout budgets.
// Keep headroom by default; --jobs remains an explicit concurrency override.
return Math.min(8, Math.max(1, Math.ceil(cpus * 4 / 3)));
}
export function parseJobs(args: string[]): number {
@@ -71,7 +72,7 @@ export function shardRustCommand(
const serial = ["worker", "worker-runtime", "yoi-workspace-server"].includes(
task.name.split("/")[0],
);
if (names.length <= 72) {
if (names.length <= (serial ? 36 : 72)) {
return [{
task: serial
? { ...task, args: [...task.args, "--test-threads", "1"] }
@@ -79,7 +80,9 @@ export function shardRustCommand(
selectedNames: [...names],
}];
}
const count = Math.min(32, Math.ceil(names.length / 36));
// Shard size and concurrency are independent: a growing test inventory must
// not silently pack more serial cases into the same fixed timeout window.
const count = Math.ceil(names.length / 36);
const shards: string[][] = Array.from({ length: count }, () => []);
names.forEach((name, index) => shards[index % count].push(name));
return shards.map((selectedNames, index) => ({