-
Notifications
You must be signed in to change notification settings - Fork 29
Make generated Jass comparable across runs, and cut the suite from 13 to 7 minutes #1235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b25a33b
4ef22da
5773d1c
bd64d08
83d0e08
9f6e101
b9fda9d
ce3a1ea
7fa5c15
886f556
5ccc791
25931aa
96f8e2a
704691e
a87a8cc
645b943
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -235,15 +235,85 @@ tasks.named('compileJava') { it.dependsOn('gen') } | |
|
|
||
| /** -------- Tests -------- */ | ||
|
|
||
| /** | ||
| * How many test workers to run at once. | ||
| * | ||
| * Cores decide how much parallelism is useful; memory decides how much is survivable. Each worker | ||
| * is a JVM with the heap set below, and the Gradle daemon holds its own on top, so a machine with | ||
| * many cores and little memory has to be counted the other way. Measured on eight cores: serial | ||
| * 13m11s, four forks 8m39s, eight forks 7m03s — more forks kept winning even though each test runs | ||
| * slower under the contention, so this errs towards cores where memory allows. | ||
| */ | ||
| int testForkCount() { | ||
| def override = project.findProperty('testForks') | ||
| if (override) { | ||
| return Math.max(1, override.toString().toInteger()) | ||
| } | ||
| int byCores = Math.max(1, (int) (Runtime.runtime.availableProcessors() / 2)) | ||
| int workerHeapGb = 2 // keep in step with -Xmx below | ||
| int reservedGb = 4 // the daemon's own heap, plus room for the OS and the lua/pjass runs | ||
| try { | ||
| def os = java.lang.management.ManagementFactory.operatingSystemMXBean | ||
| long totalBytes = os."getTotalMemorySize"() | ||
| int byMemory = (int) ((totalBytes / (1024L * 1024L * 1024L) - reservedGb) / workerHeapGb) | ||
| return Math.max(1, Math.min(byCores, byMemory)) | ||
| } catch (Throwable ignored) { | ||
| // No reliable reading of physical memory; cores alone, conservatively. | ||
| return Math.max(1, Math.min(byCores, 4)) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Fetches the standard library the tests compile against, once, before they fork. | ||
| * | ||
| * StdLib guards the fetch with a lock held in one process, which is no guard at all across | ||
| * workers: on a clean checkout each of them would clone into the same directory at the same time. | ||
| * The pinned repository and commit stay defined in that one place rather than being repeated here. | ||
| */ | ||
| tasks.register('ensureStdLib', JavaExec) { | ||
| description "Fetches the pinned standard library used by the tests" | ||
| classpath = sourceSets.test.runtimeClasspath | ||
| mainClass.set('tests.wurstscript.tests.StdLib') | ||
| workingDir = projectDir | ||
| // An escape hatch for working without the network: a focused run of tests that never touch | ||
| // the library should not be stopped by not being able to reach GitHub. Read now rather than | ||
| // when the task runs, which the configuration cache does not allow. | ||
| def skipFetch = project.hasProperty('skipStdLibFetch') | ||
| onlyIf { !skipFetch } | ||
| // Deliberately not declaring the checkout as an output: that would skip this whenever the | ||
| // directory merely exists, which is precisely when it may be at the wrong commit or half | ||
| // cloned. The fetch checks the pinned commit and repairs it, and costs nothing when correct. | ||
| outputs.upToDateWhen { false } | ||
| } | ||
|
|
||
| test { | ||
| dependsOn 'ensureStdLib' | ||
|
Comment on lines
290
to
+291
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the pinned checkout is absent or stale and GitHub is unavailable, this unconditional dependency makes even AGENTS.md reference: AGENTS.md:L97-L103 Useful? React with 👍 / 👎. |
||
| useTestNG() | ||
|
|
||
| // The suite is a few thousand independent compilations and was running one at a time, so it | ||
| // took as long as the sum of them. Forks rather than threads: the harness keeps state in | ||
| // statics (the current test environment, the global caches, the extracted lua binaries), and a | ||
| // fork gets its own copy of all of it. Gradle hands out whole classes, so a class that writes | ||
| // fixed file names stays inside one fork. | ||
| // Wall time cannot fall below the slowest single class, which is why this does not need to be | ||
| // every core to get most of the win. | ||
| // | ||
| // Bounded by memory as well as cores, because the two are not proportional everywhere: a CI | ||
| // runner with sixteen cores and eight gigabytes would otherwise start eight two-gigabyte | ||
| // workers next to the daemon's own three and be killed for it. Override with -PtestForks=N. | ||
| maxParallelForks = testForkCount() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On a clean checkout whenever this resolves above one, independent worker JVMs can concurrently enter AGENTS.md reference: AGENTS.md:L60-L63 Useful? React with 👍 / 👎. |
||
|
|
||
| jvmArgs( | ||
| '-Xmx2g', // local: give it room to finish and dump | ||
| '-XX:MaxMetaspaceSize=256m', | ||
| '-XX:+HeapDumpOnOutOfMemoryError', | ||
| '-XX:+UnlockExperimentalVMOptions', // needed for UseCompactObjectHeaders until it graduates | ||
| '-XX:+UseCompactObjectHeaders', // Java 24+: 8-byte headers (vs 16) — big win for AST-heavy workloads | ||
| // Each fork otherwise sizes its garbage collector and compiler threads for the whole | ||
| // machine, so running several at once oversubscribes it badly: eight forks made every | ||
| // test about three times slower and gave back only a third of the parallelism. | ||
| '-XX:ActiveProcessorCount=2', | ||
| ) | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
temp/WurstStdlib2is an existing detached or shallow checkout without a localmasterref, this dependency makes every test enter the repair path, butStdLib.downloadStandardlib()checks outmasterbefore fetching it (StdLib.java:76). I reproduced this with the repository's prepopulated detached checkout: even an unrelated focused test failed inensureStdLibwithRef master cannot be resolved. Fetch/create the remote tracking ref or reclone an invalid checkout before attempting the checkout so a stale cache does not block the entire suite.Useful? React with 👍 / 👎.