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

Enable emscripten build with parallelization #1045

Merged
merged 2 commits into from
Nov 27, 2024
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: 1 addition & 1 deletion .github/workflows/manifold.yml
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ jobs:
timeout-minutes: 30
strategy:
matrix:
variant: [manifold-none, manifold-tbb, manifold-js, manifold3d]
variant: [manifold-none, manifold-tbb, manifold-js, manifold-js-tbb, manifold3d]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
4 changes: 0 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,6 @@ if(EMSCRIPTEN)
if(MANIFOLD_PAR)
set(CMAKE_THREAD_LIBS_INIT "-pthread")
add_compile_options(-pthread)
# PTHREAD_POOL_SIZE is set to 4 for OK-ish performance, in general we are
# not getting too much speedup for very large number of cores, and a lot of
# CPUs now have 4 cores...
add_link_options(-sPTHREAD_POOL_SIZE=4)
# mimalloc is needed for good performance
add_link_options(-sMALLOC=mimalloc)
# The default stack size apparently causes problem when parallelization is
Expand Down
4 changes: 4 additions & 0 deletions bindings/wasm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ add_custom_target(
add_custom_command(
TARGET js_deps
POST_BUILD
# fix js file
COMMAND
${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/fixup.py
${CMAKE_CURRENT_BINARY_DIR}/manifold.js
# copy WASM build back here for publishing to npm
COMMAND
${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/manifold.*
Expand Down
26 changes: 26 additions & 0 deletions bindings/wasm/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@
#include "manifold/manifold.h"
#include "manifold/polygon.h"

#if (MANIFOLD_PAR == 1)
#include <tbb/parallel_for.h>

#include <atomic>
#endif

// https://github.com/oneapi-src/oneTBB/blob/master/WASM_Support.md#limitations
void initTBB() {
#if (MANIFOLD_PAR == 1)
int num_threads = tbb::this_task_arena::max_concurrency();
std::atomic<int> barrier{num_threads};
tbb::parallel_for(
0, num_threads,
[&barrier](int) {
barrier--;
while (barrier > 0) {
// Send browser thread to event loop
std::this_thread::yield();
}
},
tbb::static_partitioner{});
#endif
}

using namespace emscripten;
using namespace manifold;

Expand Down Expand Up @@ -195,4 +219,6 @@ EMSCRIPTEN_BINDINGS(whatever) {
function("setCircularSegments", &Quality::SetCircularSegments);
function("getCircularSegments", &Quality::GetCircularSegments);
function("resetToCircularDefaults", &Quality::ResetToDefaults);

function("initTBB", &initTBB);
}
3 changes: 3 additions & 0 deletions bindings/wasm/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Module.setup = function() {
if (_ManifoldInitialized) return;
_ManifoldInitialized = true;

// warmup tbb for emscripten, according to
// https://github.com/oneapi-src/oneTBB/blob/master/WASM_Support.md#limitations
Module.initTBB();
// conversion utilities

function toVec(vec, list, f = x => x) {
Expand Down
6 changes: 6 additions & 0 deletions bindings/wasm/examples/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export default defineConfig({
worker: {
format: 'es',
},
server: {
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
},
},
build: {
target: 'esnext',
sourcemap: true,
Expand Down
19 changes: 19 additions & 0 deletions bindings/wasm/fixup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
import sys

if len(sys.argv) != 2:
print("Usage: python fixup.py <SOURCE_DIR>")

filename = sys.argv[1]
with open(filename, "r") as file:
data = file.read()

data = data.replace(
'var workerOptions={type:"module",workerData:"em-pthread",name:"em-pthread"};', ""
)
data = data.replace(
"workerOptions", '{type:"module",workerData:"em-pthread",name:"em-pthread"}'
Copy link
Owner

Choose a reason for hiding this comment

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

What is this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

emscripten generating some non-static worker options that Vite cannot handle, and it can be trivially modified to become static.

)

with open(filename, "w") as file:
file.write(data)
2 changes: 1 addition & 1 deletion bindings/wasm/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ Manifold SetProperties(Manifold& manifold, int numProp, uintptr_t funcPtr) {
Manifold LevelSet(uintptr_t funcPtr, Box bounds, double edgeLength,
double level, double tolerance) {
double (*f)(const vec3&) = reinterpret_cast<double (*)(const vec3&)>(funcPtr);
return Manifold::LevelSet(f, bounds, edgeLength, level, tolerance);
return Manifold::LevelSet(f, bounds, edgeLength, level, tolerance, false);
}

std::vector<Manifold> Split(Manifold& a, Manifold& b) {
Expand Down
4 changes: 4 additions & 0 deletions cmake/manifoldDeps.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ if(MANIFOLD_TEST)
endif()
endif()

if(EMSCRIPTEN)
find_package(Python REQUIRED)
endif()

if(MANIFOLD_FUZZ)
logmissingdep("fuzztest" , "MANIFOLD_FUZZ")
FetchContent_Declare(
Expand Down
6 changes: 5 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
cd ../
'';
};
manifold-emscripten = { doCheck ? true }: pkgs.buildEmscriptenPackage {
manifold-emscripten = { doCheck ? true, parallel ? false }: pkgs.buildEmscriptenPackage {
name = "manifold-js";
version = manifold-version;
src = self;
Expand All @@ -126,7 +126,9 @@
mkdir build
cd build
emcmake cmake -DCMAKE_BUILD_TYPE=Release \
-DMANIFOLD_PAR=${if parallel then "ON" else "OFF"} \
-DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=${gtest-src} \
-DFETCHCONTENT_SOURCE_DIR_TBB=${onetbb-src} \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=../clipper2 ..
'';
buildPhase = ''
Expand All @@ -148,6 +150,7 @@
manifold-tbb = manifold { };
manifold-none = manifold { parallel = false; };
manifold-js = manifold-emscripten { };
manifold-js-tbb = manifold-emscripten { parallel = true; };
# but how should we make it work with other python versions?
manifold3d = with pkgs.python3Packages; buildPythonPackage {
pname = "manifold3d";
Expand Down Expand Up @@ -197,6 +200,7 @@
# useful tools
clang-tools_18
clang_18
llvmPackages_18.bintools
tracy
];
};
Expand Down
21 changes: 21 additions & 0 deletions test/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "manifold/polygon.h"
#include "test.h"

#if (MANIFOLD_PAR == 1)
#include <tbb/parallel_for.h>
#endif

// we need to call some tracy API to establish the connection
#if __has_include(<tracy/Tracy.hpp>)
#include <tracy/Tracy.hpp>
Expand Down Expand Up @@ -45,6 +49,23 @@ int main(int argc, char** argv) {
const char* name = "test setup";
FrameMarkStart(name);

// warmup tbb for emscripten, according to
// https://github.com/oneapi-src/oneTBB/blob/master/WASM_Support.md#limitations
#if defined(__EMSCRIPTEN__) && (MANIFOLD_PAR == 1)
int num_threads = tbb::this_task_arena::max_concurrency();
std::atomic<int> barrier{num_threads};
tbb::parallel_for(
0, num_threads,
[&barrier](int) {
barrier--;
while (barrier > 0) {
// Send browser thread to event loop
std::this_thread::yield();
}
},
tbb::static_partitioner{});
#endif

for (int i = 1; i < argc; i++) {
if (argv[i][0] != '-') {
fprintf(stderr, "Unknown option: %s\n", argv[i]);
Expand Down