Skip to content
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

Working (but slow) support for pthreads + memory growth #8365

Merged
merged 37 commits into from
Apr 8, 2019
Merged

Conversation

kripken
Copy link
Member

@kripken kripken commented Mar 28, 2019

(in wasm - no support in asm.js)

Background: WebAssembly/design#1271

  • Add GROWABLE_HEAP_* methods that replace each load and store in JS. These safely check if memory grew, and updates the buffer and views if so. The JS optimizer is used to instrument the JS in this way, so it works for user JS as well.
  • Show a warning about the slowness during compilation.
  • Proxy emscripten_resize_heap to the main thread, and handle races where a thread asks for growth but another thread grows it to a lower or higher value meanwhile - loop until successful, or an error is hit.
  • Make sbrk threadsafe using that.
  • Rewrite brk using sbrk, to avoid writing two pieces of threadsafe code.

Blocked on https://bugs.chromium.org/p/v8/issues/detail?id=9062 , so this is not fully tested yet - it doesn't test an actual memory growth, but it does test that instrumenting the code works.

@kripken kripken requested a review from dschuff March 28, 2019 22:18
@kripken
Copy link
Member Author

kripken commented Mar 28, 2019

Ah, I see some errors on CI that I missed in the subset of tests I ran locally. I don't see a way to turn this into a draft PR - is there? Anyhow, this is still a wip.

@kripken kripken removed the request for review from dschuff March 28, 2019 23:18
pthread_t thr;

printf("start\n");
EM_ASM({ assert(HEAP8.length === 32 * 1024 * 1024, "start at 32MB") });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use EM_JS?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it's just test code, and convenient to do it all on a single line? Maybe I don't see the benefit to using EM_JS here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no benefit, other than everything should use EM_JS unless there's a good reason not to?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general yeah, but it's just not inline, so it's more typing and less immediately obvious to the reader - the only advantages of EM_ASM, basically. I agree EM_JS is the preferred thing for most normal code though.

@kripken
Copy link
Member Author

kripken commented Mar 30, 2019

Ok, I pushed a fix for modularize here. I ran into some MODULARIZE_INSTANCE pre-existing bugs, which I opened #8372 for, and which should land before this.

Thanks for testing @Brion! Which HEAP* accessors did you need to change? Any emscripten code or code that is optimized with it (pre-js etc.) should be ok. The only risk is completely external JS, is that the case you are seeing?

In general it's safest to use those special GROWABLE_HEAP_* accessors - we may want to make them exportable, and could make them also work in asm.js mode. Otherwise, anywhere you receive a pointer to memory from somewhere else is a place you must check if memory was grown, as it could be a pointer into higher memory than existed before. So around any such pointer arrival you could, if in wasm + pthreads + growth, check and recreate the buffer views. We could perhaps create a function for that, updateHeapViews perhaps, that is a no-op in all modes but wasm + pthreads + growth (but you'd be responsible for placing it in the right places).

@bvibber
Copy link
Collaborator

bvibber commented Mar 30, 2019

Yeah these are in my custom JS library mix-ins, where I either malloc a buffer and write into it or create a typed array view for a C-created buffer to take data out. I'm not doing a lot of individual loads/stores; mostly data's coming as arguments on a callback, some of which are pointers/length pairs for buffers to export, which may be beyond the end of the old buffer views.

I think it should work to run updateGlobalBufferViews() manually before making a subview directly from HEAPU8, HEAPF32 etc, but I think that's going to be error-prone as forgetting will sometimes work, sometimes not.

It might feel more natural to have view-creation accessors that wrap that check-and-update call, like:

GROWABLE_HEAP_VIEW_U32(start, end)

@kripken
Copy link
Member Author

kripken commented Apr 1, 2019

Yeah, view creators are a natural fit too, added now.

Also added docs about this.

@bvibber
Copy link
Collaborator

bvibber commented Apr 2, 2019

The view accessors look perfect, thanks!

src/preamble.js Outdated
#endif

#if MODULARIZE
// In modularize mode the wasmMemory and others are received in an onmessage, and that
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be "in pthreads mode" rather than "modularize mode"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing comment.

pthread_t thr;

printf("start\n");
EM_ASM({ assert(HEAP8.length === 32 * 1024 * 1024, "start at 32MB") });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no benefit, other than everything should use EM_JS unless there's a good reason not to?

def test_pthread_growth_mainthread(self):
def run(emcc_args=[]):
# Note that this test may not pass on Chrome until 75, due to https://bugs.chromium.org/p/v8/issues/detail?id=9062
self.btest(path_from_root('tests', 'pthread', 'test_pthread_memory_growth_mainthread.c'), expected='1', args=['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'TOTAL_MEMORY=32MB', '-s', 'WASM_MEM_MAX=256MB'] + emcc_args, also_asmjs=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should test in PROXY_TO_PTHREAD mode too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that won't work yet because of chromium issue 9065, same as test_pthread_growth. I'll add a PROXY_TO_PTHREAD mode in that test.

@@ -5887,6 +5887,73 @@ function safeHeap(ast) {
});
}

function growableHeap(ast) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this have some comment like "transform HEAP8 etc heap accesses to calls to GROWABLE_HEAP_LOAD_I8" or something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a comment.

@kripken
Copy link
Member Author

kripken commented Apr 5, 2019

I tried to use chrome unstable so that at least part of the new tests here could pass, but it fails on unrelated things on circle, so that'll need to be looked at separately. As a result, for now the new tests are disabled.

@kripken kripken merged commit e172838 into incoming Apr 8, 2019
@kripken kripken deleted the growableHeap branch April 8, 2019 21:43
VirtualTim pushed a commit to VirtualTim/emscripten that referenced this pull request May 21, 2019
…ore#8365)

(in wasm - no support in asm.js)

Background: WebAssembly/design#1271

* Add GROWABLE_HEAP_* methods that replace each load and store in JS. These safely check if memory grew, and updates the buffer and views if so. The JS optimizer is used to instrument the JS in this way, so it works for user JS as well.
* Show a warning about the slowness during compilation.
* Make sbrk etc. threadsafe.
 * Rewrite brk using sbrk, to avoid writing two pieces of threadsafe code.
VirtualTim added a commit to VirtualTim/emscripten that referenced this pull request May 23, 2019
VirtualTim added a commit to VirtualTim/emscripten that referenced this pull request May 23, 2019
belraquib pushed a commit to belraquib/emscripten that referenced this pull request Dec 23, 2020
…ore#8365)

(in wasm - no support in asm.js)

Background: WebAssembly/design#1271

* Add GROWABLE_HEAP_* methods that replace each load and store in JS. These safely check if memory grew, and updates the buffer and views if so. The JS optimizer is used to instrument the JS in this way, so it works for user JS as well.
* Show a warning about the slowness during compilation.
* Make sbrk etc. threadsafe.
 * Rewrite brk using sbrk, to avoid writing two pieces of threadsafe code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants