Skip to content

Add 2GB-4GB heap testing #10811

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

Merged
merged 20 commits into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,7 @@ LibraryManager.library = {
#endif
],
emscripten_resize_heap: function(requestedSize) {
#if CAN_ADDRESS_2GB
requestedSize = requestedSize >>> 0;
#endif
#if ALLOW_MEMORY_GROWTH == 0
#if ABORTING_MALLOC
abortOnCannotGrowMemory(requestedSize);
Expand Down
25 changes: 25 additions & 0 deletions tests/browser/test_2GB_fail.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <assert.h>
#include <emscripten.h>
#include <stdio.h>
#include <stdlib.h>

void* allocation;

int main() {
const int CHUNK_SIZE = 100 * 1024 * 1024;
const int NUM_CHUNKS = 31; // total allocation will be over 3GB

puts("allocating");

for (int i = 0; i < NUM_CHUNKS; i++) {
printf("alloc %d\n", i);
allocation = malloc(CHUNK_SIZE);
if (!allocation) {
assert(i <= 20); // can't get to 2GB
puts("expected allocation failure");
return 0;
}
}

puts("UNEXPECTED");
}
1 change: 1 addition & 0 deletions tests/browser/test_2GB_fail.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
expected allocation failure
38 changes: 38 additions & 0 deletions tests/browser/test_4GB.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <assert.h>
#include <emscripten.h>
#include <stdio.h>
#include <vector>

int main() {
const int CHUNK_SIZE = 100 * 1024 * 1024;
const int NUM_CHUNKS = 31; // total allocation will be over 3GB

std::vector<std::vector<char>> chunks;
chunks.resize(NUM_CHUNKS);

puts("allocating");

for (int i = 0; i < NUM_CHUNKS; i++) {
printf("alloc %d\n", i);
chunks[i].resize(CHUNK_SIZE);
}

puts("testing");

for (int i = 0; i < NUM_CHUNKS; i++) {
printf("test %d\n", i);
chunks[i][i] = i;
int fromJS = EM_ASM_INT({
return HEAP8[$0];
}, &chunks[i][i]);
printf("wrote %d in C, read %d from JS\n", i, fromJS);
EM_ASM_INT({
HEAP8[$0] = 2 * $1;
}, &chunks[i][i], i);
int fromC = chunks[i][i];
printf("wrote %d in JS, read %d from C\n", 2 * i, fromC);
}

puts("success");
}

127 changes: 127 additions & 0 deletions tests/browser/test_4GB.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
allocating
alloc 0
alloc 1
alloc 2
alloc 3
alloc 4
alloc 5
alloc 6
alloc 7
alloc 8
alloc 9
alloc 10
alloc 11
alloc 12
alloc 13
alloc 14
alloc 15
alloc 16
alloc 17
alloc 18
alloc 19
alloc 20
alloc 21
alloc 22
alloc 23
alloc 24
alloc 25
alloc 26
alloc 27
alloc 28
alloc 29
alloc 30
testing
test 0
wrote 0 in C, read 0 from JS
wrote 0 in JS, read 0 from C
test 1
wrote 1 in C, read 1 from JS
wrote 2 in JS, read 2 from C
test 2
wrote 2 in C, read 2 from JS
wrote 4 in JS, read 4 from C
test 3
wrote 3 in C, read 3 from JS
wrote 6 in JS, read 6 from C
test 4
wrote 4 in C, read 4 from JS
wrote 8 in JS, read 8 from C
test 5
wrote 5 in C, read 5 from JS
wrote 10 in JS, read 10 from C
test 6
wrote 6 in C, read 6 from JS
wrote 12 in JS, read 12 from C
test 7
wrote 7 in C, read 7 from JS
wrote 14 in JS, read 14 from C
test 8
wrote 8 in C, read 8 from JS
wrote 16 in JS, read 16 from C
test 9
wrote 9 in C, read 9 from JS
wrote 18 in JS, read 18 from C
test 10
wrote 10 in C, read 10 from JS
wrote 20 in JS, read 20 from C
test 11
wrote 11 in C, read 11 from JS
wrote 22 in JS, read 22 from C
test 12
wrote 12 in C, read 12 from JS
wrote 24 in JS, read 24 from C
test 13
wrote 13 in C, read 13 from JS
wrote 26 in JS, read 26 from C
test 14
wrote 14 in C, read 14 from JS
wrote 28 in JS, read 28 from C
test 15
wrote 15 in C, read 15 from JS
wrote 30 in JS, read 30 from C
test 16
wrote 16 in C, read 16 from JS
wrote 32 in JS, read 32 from C
test 17
wrote 17 in C, read 17 from JS
wrote 34 in JS, read 34 from C
test 18
wrote 18 in C, read 18 from JS
wrote 36 in JS, read 36 from C
test 19
wrote 19 in C, read 19 from JS
wrote 38 in JS, read 38 from C
test 20
wrote 20 in C, read 20 from JS
wrote 40 in JS, read 40 from C
test 21
wrote 21 in C, read 21 from JS
wrote 42 in JS, read 42 from C
test 22
wrote 22 in C, read 22 from JS
wrote 44 in JS, read 44 from C
test 23
wrote 23 in C, read 23 from JS
wrote 46 in JS, read 46 from C
test 24
wrote 24 in C, read 24 from JS
wrote 48 in JS, read 48 from C
test 25
wrote 25 in C, read 25 from JS
wrote 50 in JS, read 50 from C
test 26
wrote 26 in C, read 26 from JS
wrote 52 in JS, read 52 from C
test 27
wrote 27 in C, read 27 from JS
wrote 54 in JS, read 54 from C
test 28
wrote 28 in C, read 28 from JS
wrote 56 in JS, read 56 from C
test 29
wrote 29 in C, read 29 from JS
wrote 58 in JS, read 58 from C
test 30
wrote 30 in C, read 30 from JS
wrote 60 in JS, read 60 from C
success
20 changes: 20 additions & 0 deletions tests/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,26 @@ def do_run_from_file(self, src, expected_output, *args, **kwargs):
logger.debug('do_run_from_file: %s' % src)
self.do_run(open(src).read(), open(expected_output).read(), *args, **kwargs)

def do_run_in_out_file_test(self, *path, **kwargs):
test_path = path_from_root(*path)

def find_files(*ext_list):
ret = None
count = 0
for ext in ext_list:
if os.path.isfile(test_path + ext):
ret = test_path + ext
count += 1
assert count > 0, ("No file found at {} with extension {}"
.format(test_path, ext_list))
assert count <= 1, ("Test file {} found with multiple valid extensions {}"
.format(test_path, ext_list))
return ret

src = find_files('.c', '.cpp')
output = find_files('.out', '.txt')
self.do_run_from_file(src, output, **kwargs)

## Does a complete test - builds, runs, checks output, etc.
def do_run(self, src, expected_output, args=[], output_nicerizer=None,
no_build=False, main_file=None, additional_files=[],
Expand Down
29 changes: 28 additions & 1 deletion tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from runner import BrowserCore, path_from_root, has_browser, EMTEST_BROWSER, no_fastcomp, no_wasm_backend, create_test_file, parameterized, ensure_dir
from tools import system_libs
from tools.shared import PYTHON, EMCC, WINDOWS, FILE_PACKAGER, PIPE, SPIDERMONKEY_ENGINE, JS_ENGINES
from tools.shared import PYTHON, EMCC, WINDOWS, FILE_PACKAGER, PIPE, SPIDERMONKEY_ENGINE, V8_ENGINE, JS_ENGINES
from tools.shared import try_delete, run_process, run_js, Building

try:
Expand Down Expand Up @@ -5002,3 +5002,30 @@ def test_pthread_modularize_export_name(self):

def test_system(self):
self.btest(path_from_root('tests', 'system.c'), '0')

@no_fastcomp('only upstream supports 4GB')
@no_firefox('no 4GB support yet')
def test_zzz_zzz_4GB(self):
# TODO Convert to an actual browser test when it reaches stable.
# For now, keep this in browser as this suite runs serially, which
# means we don't compete for memory with anything else (and run it
# at the very very end, to reduce the risk of it OOM-killing the
# browser).

# test that we can allocate in the 2-4GB range, if we enable growth and
# set the max appropriately
self.emcc_args += ['-O2', '-s', 'ALLOW_MEMORY_GROWTH', '-s', 'MAXIMUM_MEMORY=4GB', '-s', 'ASSERTIONS']
self.do_run_in_out_file_test('tests', 'browser', 'test_4GB', js_engines=[V8_ENGINE])

@no_fastcomp('only upstream supports 4GB')
def test_zzz_zzz_2GB_fail(self):
# TODO Convert to an actual browser test when it reaches stable.
# For now, keep this in browser as this suite runs serially, which
# means we don't compete for memory with anything else (and run it
# at the very very end, to reduce the risk of it OOM-killing the
# browser).

# test that growth doesn't go beyond 2GB without the max being set for that,
# and that we can catch an allocation failure exception for that
self.emcc_args += ['-O2', '-fexceptions', '-s', 'ALLOW_MEMORY_GROWTH', '-s', 'MAXIMUM_MEMORY=2GB', '-s', 'ASSERTIONS']
self.do_run_in_out_file_test('tests', 'browser', 'test_2GB_fail', js_engines=[V8_ENGINE])
20 changes: 0 additions & 20 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,26 +317,6 @@ def maybe_closure(self):
return True
return False

def do_run_in_out_file_test(self, *path, **kwargs):
test_path = path_from_root(*path)

def find_files(*ext_list):
ret = None
count = 0
for ext in ext_list:
if os.path.isfile(test_path + ext):
ret = test_path + ext
count += 1
assert count > 0, ("No file found at {} with extension {}"
.format(test_path, ext_list))
assert count <= 1, ("Test file {} found with multiple valid extensions {}"
.format(test_path, ext_list))
return ret

src = find_files('.c', '.cpp')
output = find_files('.out', '.txt')
self.do_run_from_file(src, output, **kwargs)

def verify_in_strict_mode(self, filename):
with open(filename) as infile:
js = infile.read()
Expand Down