~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

The slowest test binaries run more of their tests at once

Closed chadtmiller.com asked to merge into main from chadtmiller.com/knotless:perf/run-tests
harness/cov.mjs+31−0
@@ -49,6 +49,18 @@
// a PDS without spaces, which only those binaries' tests reach. A line
// that falls short with it names a binary to add.
//
// A test binary runs as many of its tests at once as the CPUs it is
// given, as libtest reads the cgroup, which for the integration tests is
// too few: they wait on their harness, their runner and git far more than
// they compute, so one in a container of 4 CPUs used under one of them,
// and its slowest binary, run 4 tests at a time, set the whole run's
// length. So a binary takes a thread for each two minutes of its last
// run's thread time (its length times the threads it had, which more
// threads do not change), never fewer than the CPUs and at most
// COV_TEST_THREADS (8): the long ones finish nearer the short ones, and
// the rest are left as they were. RUST_TEST_THREADS, set, is kept for
// every binary.
//
// COV_JOBS sets how many run at once; COV_CLEAN=1 builds every workspace
// crate again first; COV_ONLY=a,b runs only the test binaries named, to
// try something quickly (failing the gate); COV_TOOLCHAIN names the
@@ -135,6 +147,16 @@ const buildJobs = () => {
return caps.length ? Math.max(1, Math.min(...caps)) : undefined
}
const limited = buildJobs()
const [quota, period] = cgroup('cpu.max').split(' ')
const cpus = quota === 'max' ? availableParallelism() : Math.max(1, Math.floor(quota / period))
const threadsMax = Number(process.env.COV_TEST_THREADS) || 8
/// How many of `t`'s tests run at once (see the top).
const threadsOf = (t) => {
if (process.env.RUST_TEST_THREADS) return Number(process.env.RUST_TEST_THREADS)
const ms = times[timeKey(t)] ?? 0
const had = times[`${timeKey(t)} threads`] ?? cpus
return Math.max(cpus, Math.min(threadsMax, Math.ceil((ms * had) / 120_000)))
}
if (!env.CARGO_BUILD_JOBS && limited) {
env.CARGO_BUILD_JOBS = String(limited)
console.log(
@@ -415,6 +437,11 @@ if (reused.length)
if (runs.length) {
for (const n of Object.values(nets).flat()) n.file = await n.up
console.log(`harnesses up in ${took()}`)
const more = runs.filter((r) => threadsOf(r) > cpus)
if (more.length)
console.log(
`more than ${cpus} tests at once: ${more.map((r) => `${r.net} ${r.name} ${threadsOf(r)}`).join(', ')}`,
)
}
let dirs = 0
@@ -429,6 +456,7 @@ const one = (t, args = []) =>
const plans = `${profiles}-plans`
rmSync(plans, { recursive: true, force: true })
const began = Date.now()
const threads = threadsOf(t)
// The least busy harness of its net.
const net = nets[t.net].reduce((a, b) => (b.busy < a.busy ? b : a))
net.busy++
@@ -440,6 +468,7 @@ const one = (t, args = []) =>
KNOTLESS_TEST_NET: net.file,
KNOTLESS_DEV_ENV: t.net === 'spaces' ? spaces : '',
CARGO_MANIFEST_DIR: t.dir,
RUST_TEST_THREADS: String(threads),
KNOTLESS_ANSWERS: answers,
KNOTLESS_PLANS: plans,
},
@@ -465,6 +494,7 @@ const one = (t, args = []) =>
timedOut,
out,
ms: Date.now() - began,
threads,
profiles,
answers,
plans,
@@ -549,6 +579,7 @@ const runAll = async (list) => {
continue
}
times[timeKey(r)] = r.ms
times[`${timeKey(r)} threads`] = r.threads
for (const f of readdirSync(r.profiles)) profile(join(r.profiles, f))
answer(r.answers)
plan(r.plans)