Make wasm test faster (#8829)

show in developer changelog
This commit is contained in:
Clément Pasteau
2026-07-15 09:29:13 +02:00
committed by GitHub
parent a8c4ad8180
commit 0cd03bbfa1
7 changed files with 534 additions and 1002 deletions
+7 -1
View File
@@ -326,7 +326,13 @@ jobs:
- run:
name: Run tests
command: cd GDevelop.js && npm run test -- --maxWorkers=4
# Tests are slow under ASan and jest (in a non-TTY environment) only prints
# output when a whole test file finishes, so allow long silences instead of
# killing the step after the default 10 minutes without output.
no_output_timeout: 30m
# malloc_context_size: record fewer stack frames on each malloc/free (default
# is 30) - a small, free speedup that only shortens traces in ASan reports.
command: cd GDevelop.js && ASAN_OPTIONS=malloc_context_size=5 npm run test -- --maxWorkers=4
# Upload artifacts (CircleCI)
- store_artifacts:
+9 -2
View File
@@ -1,7 +1,14 @@
// If running under ASAN, disable the "container overflow" checks because of false positives
// with std::vector<gd::String>. See https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow.
if (Module['ASAN_OPTIONS'] === undefined)
Module['ASAN_OPTIONS'] ='detect_container_overflow=0';
// Also append options from the ASAN_OPTIONS environment variable when running in Node.js,
// as Emscripten only reads them from Module['ASAN_OPTIONS'] (not from the environment).
if (Module['ASAN_OPTIONS'] === undefined) {
var envAsanOptions =
typeof process !== 'undefined' && process.env && process.env.ASAN_OPTIONS
? ':' + process.env.ASAN_OPTIONS
: '';
Module['ASAN_OPTIONS'] = 'detect_container_overflow=0' + envAsanOptions;
}
// Prevent calling process["exit"] when there is a abort/runtime crash
// (useful for tests when running ASAN, to see the logs).
+3 -1
View File
@@ -23,7 +23,7 @@ elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-assertions")
# Debug with assertions: no optimization.
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Debugging + profiling support
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-sanitizers")
# Debug with sanitizers: no optimization.
# Debug with sanitizers (note: -O3 from the Release build type still applies at compile time).
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Debugging + profiling support
add_compile_options(-fsanitize=address) # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable linking below!
# add_compile_options(-fsanitize=undefined) # Uncomment to auto-detect occurences of undefined behavior - also enable linking below!
@@ -111,6 +111,8 @@ elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-assertions")
# target_link_libraries(--memoryprofiler) # Uncomment for interactive memory profiling
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-sanitizers")
message(STATUS "'debug-sanitizers' variant: enabling ASAN and other sanitizers")
target_link_libraries(GD "-O1") # Some optimization at link time (default is -O0), to make the tests run a bit faster in CI.
target_link_libraries(GD "-s INITIAL_MEMORY=512MB") # Start with a large heap: ASan needs a lot of memory (256MB quarantine for freed allocations, shadow memory) and growing the memory repeatedly has a cost. Overrides TOTAL_MEMORY set above.
target_link_libraries(GD "-fsanitize=address") # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable compiling above!
# target_link_libraries(GD "-fsanitize=undefined") # Uncomment to auto-detect occurences of undefined behavior - also enable compiling above!
target_link_libraries(GD "-fsanitize=null") # Uncomment to auto-detect occurences of undefined behavior - also enable compiling above!
+2 -1
View File
@@ -105,10 +105,11 @@ describe('libGD.js object serialization', function () {
']';
const element = gd.Serializer.fromJSON(json);
// Do NOT delete element, it's a static value.
// Round-trips back to the same JSON (also proves the large input was
// parsed correctly, not just that it didn't crash).
expect(gd.Serializer.toJSON(element)).toBe(json);
element.delete();
});
});
+478 -997
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -34,12 +34,15 @@
"grunt-shell": "^2.1.0",
"grunt-string-replace": "^1.3.1",
"jest": "^29.7.0",
"jest-light-runner": "^0.5.1",
"prettier": "^3.2.2",
"shelljs": "^0.8.4",
"webidl-tools": "github:4ian/webidl-tools#348f9c03afc9d8f278efccdd74543e265a41fd11"
},
"jest": {
"testEnvironment": "node",
"runner": "jest-light-runner",
"testSequencer": "<rootDir>/scripts/test-sequencer.js",
"transformIgnorePatterns": [
"../Binaries/embuild/GDevelop.js/libGD.js"
],
+32
View File
@@ -0,0 +1,32 @@
const Sequencer = require('@jest/test-sequencer').default;
// Test files that take much longer than the others (especially with the
// 'debug-sanitizers' build variant in CI). Jest's default sequencer only
// sorts by file size, which schedules them late: a single worker is then
// stuck running one of them while the other workers are idle, which bounds
// the total run time. Run them first instead.
const slowestTestFiles = [
'Serializer.js',
'GDJSBooleanOperatorsCodeGenerationIntegrationTests.js',
'GDJSDisabledCodeGenerationIntegrationTests.js',
];
class SlowestFirstSequencer extends Sequencer {
sort(tests) {
const defaultOrder = super.sort(Array.from(tests));
const rank = (test) => {
const index = slowestTestFiles.findIndex((fileName) =>
test.path.endsWith('/' + fileName)
);
return index === -1 ? slowestTestFiles.length : index;
};
// Stable sort: known slow files first (in the order listed above),
// then the default order (largest file first).
return defaultOrder
.map((test, index) => ({ test, index }))
.sort((a, b) => rank(a.test) - rank(b.test) || a.index - b.index)
.map(({ test }) => test);
}
}
module.exports = SlowestFirstSequencer;