Skip to content
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
7 changes: 4 additions & 3 deletions src/library_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,18 @@ var LibraryPThread = {
initMainThreadBlock: function() {
if (ENVIRONMENT_IS_PTHREAD) return;

#if PTHREAD_POOL_SIZE > 0
#if PTHREAD_POOL_SIZE
var pthreadPoolSize = {{{ PTHREAD_POOL_SIZE }}};
// Start loading up the Worker pool, if requested.
for(var i = 0; i < {{{PTHREAD_POOL_SIZE}}}; ++i) {
for(var i = 0; i < pthreadPoolSize; ++i) {
PThread.allocateUnusedWorker();
}
#endif

// In asm.js we do not need to wait for Wasm Module to compile on the main thread, so can load
// up each Worker immediately. (in asm.js mode ignore PTHREAD_POOL_DELAY_LOAD altogether for
// simplicity, as multithreading performance optimizations are not interesting there)
#if !WASM && PTHREAD_POOL_SIZE > 0
#if !WASM && PTHREAD_POOL_SIZE
addOnPreRun(function() { addRunDependency('pthreads'); });
var numWorkersToLoad = PThread.unusedWorkers.length;
PThread.unusedWorkers.forEach(function(w) { PThread.loadWasmModuleToWorker(w, function() {
Expand Down
4 changes: 2 additions & 2 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ function createWasm() {
wasmModule = module;
// Instantiation is synchronous in pthreads and we assert on run dependencies.
if (!ENVIRONMENT_IS_PTHREAD) {
#if PTHREAD_POOL_SIZE > 0
#if PTHREAD_POOL_SIZE
var numWorkersToLoad = PThread.unusedWorkers.length;
PThread.unusedWorkers.forEach(function(w) { PThread.loadWasmModuleToWorker(w, function() {
#if !PTHREAD_POOL_DELAY_LOAD
Expand All @@ -934,7 +934,7 @@ function createWasm() {
#endif
})});
#endif
#if PTHREAD_POOL_DELAY_LOAD || PTHREAD_POOL_SIZE == 0
#if PTHREAD_POOL_DELAY_LOAD || !PTHREAD_POOL_SIZE
// PTHREAD_POOL_DELAY_LOAD==1 (or no preloaded pool in use): do not wait up for the Workers to
// instantiate the Wasm module, but proceed with main() immediately.
removeRunDependency('wasm-instantiate');
Expand Down
9 changes: 8 additions & 1 deletion src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1391,8 +1391,15 @@ var USE_PTHREADS = 0;
// in which case the specified number of Workers will be preloaded into a pool
// before the application starts, and that many threads can then be available
// for synchronous creation.
// Note that this setting is a string, and will be emitted in the JS code
// (directly, with no extra quotes) so that if you set it to '5' then 5 workers
// will be used in the pool, and so forth. The benefit of this being a string
// is that you can set it to something like
// 'navigator.hardwareConcurrency' (which will use the number of cores the
// browser reports, and is how you can get exactly enough workers for a
// threadpool equal to the number of cores).
// [link] - affects generated JS runtime code at link time
var PTHREAD_POOL_SIZE = 0;
var PTHREAD_POOL_SIZE = '';

// If your application does not need the ability to synchronously create
// threads, but it would still like to opportunistically speed up initial thread
Expand Down
87 changes: 87 additions & 0 deletions tests/pthread/test_pthread_hardware_concurrency.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2019 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <emscripten.h>
#include <emscripten/threading.h>
#include <assert.h>

#include <thread>

struct Test
{
int threadId;
};

void *ThreadMain(void *arg)
{
EM_ASM(out('Thread ' + $0 + ' finished, exit()ing.'), ((Test*)arg)->threadId);
pthread_exit(0);
}

void RunTest(int test)
{
int NUM_THREADS = std::thread::hardware_concurrency();
assert(NUM_THREADS > 0);

EM_ASM(out('Main: Test ' + $0 + ' starting, with num cores: ' + $1), test, NUM_THREADS);

struct Test t[NUM_THREADS];
pthread_t thread[NUM_THREADS];

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setstacksize(&attr, 4*1024);

printf("Main thread has thread ID %d\n", (int)pthread_self());
assert(pthread_self() != 0);

EM_ASM(out('Main: Starting test ' + $0), test);

for(int i = 0; i < NUM_THREADS; ++i)
{
t[i].threadId = i;
int rc = pthread_create(&thread[i], &attr, ThreadMain, &t[i]);
assert(rc == 0);
}

pthread_attr_destroy(&attr);

for(int i = 0; i < NUM_THREADS; ++i)
{
int status = 1;
int rc = pthread_join(thread[i], (void**)&status);
assert(rc == 0);
assert(status == 0);
}

EM_ASM(out('Main: Test ' + $0 + ' finished.'), test);
}

int main()
{
if (!emscripten_has_threading_support())
{
#ifdef REPORT_RESULT
REPORT_RESULT(0);
#endif
printf("Skipped: Threading is not supported.\n");
return 0;
}

// Do a bunch of joins, verifying the Worker pool works.
for(int i = 0; i < 7; ++i)
RunTest(i);

#ifdef REPORT_RESULT
REPORT_RESULT(0);
#else
EM_ASM(out('Main: Test successfully finished.'));
#endif
}
5 changes: 5 additions & 0 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3628,6 +3628,11 @@ def test_pthread_64bit_cxx11_atomics(self):
for pthreads in [[], ['-s', 'USE_PTHREADS=1']]:
self.btest(path_from_root('tests', 'pthread', 'test_pthread_64bit_cxx11_atomics.cpp'), expected='0', args=opt + pthreads + ['-std=c++11'])

# Test c++ std::thread::hardware_concurrency()
@requires_threads
def test_pthread_hardware_concurrency(self):
self.btest(path_from_root('tests', 'pthread', 'test_pthread_hardware_concurrency.cpp'), expected='0', args=['-O2', '-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE="navigator.hardwareConcurrency"'])

@parameterized({
'join': ('join',),
'wait': ('wait',),
Expand Down