ci: remove runner caps after timing review

This commit is contained in:
Peter Steinberger
2026-04-23 15:41:32 +01:00
parent 3e956a4982
commit dbd7966cfd
3 changed files with 109 additions and 7 deletions

View File

@@ -746,7 +746,6 @@ jobs:
timeout-minutes: 60
strategy:
fail-fast: false
max-parallel: 3
matrix: ${{ fromJson(needs.preflight.outputs.channel_contracts_matrix) }}
steps:
- name: Checkout
@@ -1119,7 +1118,6 @@ jobs:
timeout-minutes: 60
strategy:
fail-fast: false
max-parallel: 8
matrix: ${{ fromJson(needs.preflight.outputs.checks_node_core_nondist_matrix) }}
steps:
- name: Checkout
@@ -1357,7 +1355,6 @@ jobs:
timeout-minutes: 20
strategy:
fail-fast: false
max-parallel: 3
matrix:
include:
- check_name: check-preflight-guards
@@ -1498,7 +1495,6 @@ jobs:
timeout-minutes: 20
strategy:
fail-fast: false
max-parallel: 3
matrix:
include:
- check_name: check-additional-boundaries

View File

@@ -96,5 +96,6 @@ pnpm test:channels
pnpm test:contracts:channels
pnpm check:docs # docs format + lint + broken links
pnpm build # build dist when CI artifact/build-smoke lanes matter
node scripts/ci-run-timings.mjs <run-id> # summarize wall time, queue time, and slowest jobs
node scripts/ci-run-timings.mjs <run-id> # summarize wall time, queue time, and slowest jobs
node scripts/ci-run-timings.mjs --recent 10 # compare recent successful main CI runs
```

View File

@@ -70,6 +70,28 @@ function getLatestCiRunId() {
return String(runId);
}
function listRecentSuccessfulCiRuns(limit) {
const raw = execFileSync(
"gh",
[
"run",
"list",
"--branch",
"main",
"--workflow",
"CI",
"--limit",
String(Math.max(limit * 4, limit)),
"--json",
"databaseId,headSha,status,conclusion",
],
{ encoding: "utf8" },
);
return JSON.parse(raw)
.filter((run) => run.status === "completed" && run.conclusion === "success")
.slice(0, limit);
}
function loadRun(runId) {
return JSON.parse(
execFileSync(
@@ -82,6 +104,62 @@ function loadRun(runId) {
);
}
function summarizeJobs(run) {
const created = parseTime(run.createdAt);
const updated = parseTime(run.updatedAt);
const jobs = (run.jobs ?? [])
.filter((job) => !job.name?.startsWith("matrix."))
.map((job) => {
const started = parseTime(job.startedAt);
const completed = parseTime(job.completedAt);
return {
conclusion: job.conclusion ?? "",
durationSeconds: secondsBetween(started, completed),
name: job.name,
queueSeconds: secondsBetween(created, started),
started,
completed,
status: job.status,
};
})
.filter((job) => job.started !== null && job.completed !== null);
const successfulDurations = jobs
.filter((job) => job.status === "completed" && job.conclusion === "success")
.map((job) => job.durationSeconds)
.filter((duration) => duration !== null);
const firstStart = Math.min(...jobs.map((job) => job.started));
const lastComplete = Math.max(...jobs.map((job) => job.completed));
return {
avgDurationSeconds:
successfulDurations.length === 0
? null
: Math.round(
successfulDurations.reduce((sum, duration) => sum + duration, 0) /
successfulDurations.length,
),
executionWindowSeconds:
Number.isFinite(firstStart) && Number.isFinite(lastComplete)
? secondsBetween(firstStart, lastComplete)
: null,
firstQueueSeconds: Number.isFinite(firstStart) ? secondsBetween(created, firstStart) : null,
jobCount: successfulDurations.length,
maxDurationSeconds: successfulDurations.length === 0 ? null : Math.max(...successfulDurations),
p90DurationSeconds: percentile(successfulDurations, 0.9),
p95DurationSeconds: percentile(successfulDurations, 0.95),
wallSeconds: secondsBetween(created, updated),
};
}
function percentile(values, percentileValue) {
if (values.length === 0) {
return null;
}
const sorted = [...values].toSorted((left, right) => left - right);
const index = Math.min(sorted.length - 1, Math.ceil(sorted.length * percentileValue) - 1);
return sorted[index];
}
function printSection(title, jobs, metric) {
console.log(title);
for (const job of jobs) {
@@ -93,12 +171,39 @@ function printSection(title, jobs, metric) {
async function main() {
const args = process.argv.slice(2);
const recentIndex = args.indexOf("--recent");
const limitIndex = args.indexOf("--limit");
const limit =
limitIndex === -1 ? 15 : Math.max(1, Number.parseInt(args[limitIndex + 1] ?? "", 10) || 15);
if (recentIndex !== -1) {
const recentLimit = Math.max(1, Number.parseInt(args[recentIndex + 1] ?? "", 10) || 10);
for (const run of listRecentSuccessfulCiRuns(recentLimit)) {
const summary = summarizeJobs(loadRun(run.databaseId));
console.log(
[
`CI run ${run.databaseId}`,
run.headSha.slice(0, 10),
`wall=${formatSeconds(summary.wallSeconds)}`,
`exec=${formatSeconds(summary.executionWindowSeconds)}`,
`firstQueue=${formatSeconds(summary.firstQueueSeconds)}`,
`jobs=${summary.jobCount}`,
`avg=${formatSeconds(summary.avgDurationSeconds)}`,
`p90=${formatSeconds(summary.p90DurationSeconds)}`,
`p95=${formatSeconds(summary.p95DurationSeconds)}`,
`max=${formatSeconds(summary.maxDurationSeconds)}`,
].join(" "),
);
}
return;
}
const runId =
args.find((arg, index) => index !== limitIndex && index !== limitIndex + 1) ??
getLatestCiRunId();
args.find(
(arg, index) =>
index !== limitIndex &&
index !== limitIndex + 1 &&
index !== recentIndex &&
index !== recentIndex + 1,
) ?? getLatestCiRunId();
const summary = summarizeRunTimings(loadRun(runId), limit);
console.log(