fix(ci): prioritize memory-heavy unit scheduling

This commit is contained in:
Shakker 2026-03-20 04:43:09 +00:00 committed by Shakker
parent 254ea0c65e
commit d689b3fc89
3 changed files with 83 additions and 24 deletions

View File

@ -18,9 +18,8 @@ import {
loadUnitMemoryHotspotManifest,
loadTestRunnerBehavior,
loadUnitTimingManifest,
selectMemoryHeavyFiles,
selectUnitHeavyFileGroups,
packFilesByDuration,
selectTimedHeavyFiles,
} from "./test-runner-manifest.mjs";
// On Windows, `.cmd` launchers can fail with `spawn EINVAL` when invoked without a shell
@ -311,33 +310,25 @@ const memoryHeavyUnitMinDeltaKb = parseEnvNumber(
"OPENCLAW_TEST_MEMORY_HEAVY_UNIT_MIN_KB",
unitMemoryHotspotManifest.defaultMinDeltaKb,
);
const timedHeavyUnitFiles =
shouldSplitUnitRuns && heavyUnitFileLimit > 0
? selectTimedHeavyFiles({
const { memoryHeavyFiles: memoryHeavyUnitFiles, timedHeavyFiles: timedHeavyUnitFiles } =
shouldSplitUnitRuns
? selectUnitHeavyFileGroups({
candidates: allKnownUnitFiles,
limit: heavyUnitFileLimit,
minDurationMs: heavyUnitMinDurationMs,
exclude: unitBehaviorOverrideSet,
behaviorOverrides: unitBehaviorOverrideSet,
timedLimit: heavyUnitFileLimit,
timedMinDurationMs: heavyUnitMinDurationMs,
memoryLimit: memoryHeavyUnitFileLimit,
memoryMinDeltaKb: memoryHeavyUnitMinDeltaKb,
timings: unitTimingManifest,
})
: [];
const memoryHeavyUnitFiles =
shouldSplitUnitRuns && memoryHeavyUnitFileLimit > 0
? selectMemoryHeavyFiles({
candidates: allKnownUnitFiles,
limit: memoryHeavyUnitFileLimit,
minDeltaKb: memoryHeavyUnitMinDeltaKb,
exclude: unitBehaviorOverrideSet,
hotspots: unitMemoryHotspotManifest,
})
: [];
: {
memoryHeavyFiles: [],
timedHeavyFiles: [],
};
const unitSchedulingOverrideSet = new Set([...unitBehaviorOverrideSet, ...memoryHeavyUnitFiles]);
const unitFastExcludedFiles = [
...new Set([
...unitBehaviorOverrideSet,
...timedHeavyUnitFiles,
...memoryHeavyUnitFiles,
...channelSingletonFiles,
]),
...new Set([...unitSchedulingOverrideSet, ...timedHeavyUnitFiles, ...channelSingletonFiles]),
];
const unitAutoSingletonFiles = [
...new Set([...unitSingletonIsolatedFiles, ...memoryHeavyUnitFiles]),

View File

@ -168,6 +168,44 @@ export function selectMemoryHeavyFiles({
.map((entry) => entry.file);
}
export function selectUnitHeavyFileGroups({
candidates,
behaviorOverrides = new Set(),
timedLimit,
timedMinDurationMs,
memoryLimit,
memoryMinDeltaKb,
timings,
hotspots,
}) {
const memoryHeavyFiles =
memoryLimit > 0
? selectMemoryHeavyFiles({
candidates,
limit: memoryLimit,
minDeltaKb: memoryMinDeltaKb,
exclude: behaviorOverrides,
hotspots,
})
: [];
const schedulingOverrides = new Set([...behaviorOverrides, ...memoryHeavyFiles]);
const timedHeavyFiles =
timedLimit > 0
? selectTimedHeavyFiles({
candidates,
limit: timedLimit,
minDurationMs: timedMinDurationMs,
exclude: schedulingOverrides,
timings,
})
: [];
return {
memoryHeavyFiles,
timedHeavyFiles,
};
}
export function packFilesByDuration(files, bucketCount, estimateDurationMs) {
const normalizedBucketCount = Math.max(0, Math.floor(bucketCount));
if (normalizedBucketCount <= 0 || files.length === 0) {

View File

@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import {
selectMemoryHeavyFiles,
selectTimedHeavyFiles,
selectUnitHeavyFileGroups,
} from "../../scripts/test-runner-manifest.mjs";
describe("scripts/test-runner-manifest timed selection", () => {
@ -60,4 +61,33 @@ describe("scripts/test-runner-manifest memory selection", () => {
}),
).toEqual(["b.test.ts", "c.test.ts"]);
});
it("gives memory-heavy isolation precedence over timed-heavy buckets", () => {
expect(
selectUnitHeavyFileGroups({
candidates: ["overlap.test.ts", "memory-only.test.ts", "timed-only.test.ts"],
behaviorOverrides: new Set(),
timedLimit: 3,
timedMinDurationMs: 1000,
memoryLimit: 3,
memoryMinDeltaKb: 256 * 1024,
timings: {
defaultDurationMs: 250,
files: {
"overlap.test.ts": { durationMs: 5000 },
"timed-only.test.ts": { durationMs: 4200 },
},
},
hotspots: {
files: {
"overlap.test.ts": { deltaKb: 900 * 1024 },
"memory-only.test.ts": { deltaKb: 700 * 1024 },
},
},
}),
).toEqual({
memoryHeavyFiles: ["overlap.test.ts", "memory-only.test.ts"],
timedHeavyFiles: ["timed-only.test.ts"],
});
});
});