Skip to content

Commit 28107a6

Browse files
fs-eireguschmue
authored andcommitted
Upgrade emsdk version to v4.0.3 (#23633)
### Description Upgrade EMSDK to v4.0.3 ### File Size Comparison: Baseline: e666503 [[Build]](https://dev.azure.com/onnxruntime/onnxruntime/_build/results?buildId=1613209) This change: bb9f747 [[Build]](https://dev.azure.com/onnxruntime/onnxruntime/_build/results?buildId=1613180) |File | Baseline | This Change | Diff | |--|--|---|---| | ort-wasm-simd-threaded.jsep.mjs | 49,240 | 44,230 | -5,010 | | ort-wasm-simd-threaded.jsep.wasm | 22,921,505 | 21,236,866 | -1,684,639 | | ort-wasm-simd-threaded.mjs | 25,539 | 20,890 | -4,649 | | ort-wasm-simd-threaded.wasm | 11,771,161 | 10,942,193 | -828,968 | | ort.min.mjs | 345,608 | 345,608 | 0 | | ort.bundle.min.mjs | 392,960 | 388,426 | -4,534 | ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> - EMSDK 3.1.62-3.1.74 is not working because of an linker issue (wasm-ld) that causes out-of-memory or crash. - EMSDK > 3.1.69 requires a change as a post-process of the generated JS file otherwise it will fails onnxruntime-web (as a NPM package) to be consumed in user's web application because of an unexpected webpack behavior. - EMSDK >= 4.0.1 fixes the out-of-memory issue but brought new issues causes build break of an indirect dependency of ORT (ORT -> ORT-extensions -> dlib). - EMSDK 4.0.3 introduces a change that allows a previous workaround to be removed. In this PR, all of the above issues are addressed: - the linker issue (wasm-ld) is fixed in 4.0.1+ - the post-process is added in `onnxruntime_webassembly.cmake` as a `POST_BUILD` event of target `onnxruntime_webassembly`. It's done by a Node.js script that uses Regex match and replace. - `dlib` not working with EMSDK v4: - the issue is tracked at davisking/dlib#3045 - Currently no active user is using ORT extension. In this PR, removed ORT extension from the build. - file `gen_struct_info.py` is moved from `${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint` to `${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools`. This helped to remove the patch.tgz for emscripten. This change also requires a change in Dawn, so patched the change needed for Dawn in this PR.
1 parent 523f905 commit 28107a6

File tree

8 files changed

+94
-28
lines changed

8 files changed

+94
-28
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
[submodule "cmake/external/emsdk"]
88
path = cmake/external/emsdk
99
url = https://github.com/emscripten-core/emsdk.git
10-
branch = 3.1.59
10+
branch = 4.0.3

cmake/external/onnxruntime_external_deps.cmake

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ else()
510510
message("Setting pybind11_dep")
511511
set(pybind11_dep pybind11::pybind11)
512512
endif()
513-
513+
514514
endif()
515515
onnxruntime_fetchcontent_declare(
516516
onnx
@@ -559,7 +559,7 @@ if (onnxruntime_USE_XNNPACK)
559559
find_library(xnnpack_LIBRARY NAMES XNNPACK)
560560
find_library(microkernels_prod_LIBRARY NAMES microkernels-prod)
561561
find_package(unofficial-pthreadpool CONFIG REQUIRED)
562-
562+
563563
target_include_directories(xnnpack INTERFACE "${XNNPACK_HDR}")
564564
set(XNNPACK_INCLUDE_DIR ${XNNPACK_DIR}/include)
565565
set(onnxruntime_EXTERNAL_LIBRARIES_XNNPACK ${xnnpack_LIBRARY} ${microkernels_prod_LIBRARY} unofficial::pthreadpool unofficial::pthreadpool_interface)
@@ -643,10 +643,12 @@ if (onnxruntime_USE_WEBGPU)
643643
dawn
644644
URL ${DEP_URL_dawn}
645645
URL_HASH SHA1=${DEP_SHA1_dawn}
646-
# All previous patches are merged into the upstream dawn project. We don't need to apply any patches right now.
647-
# if we need to apply patches in the future, we can uncomment the following line.
648-
649-
# PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/dawn/dawn.patch
646+
# # All previous patches are merged into the upstream dawn project. We don't need to apply any patches right now.
647+
# # if we need to apply patches in the future, we can uncomment the following line.
648+
#
649+
# The dawn.patch contains the following changes:
650+
# - https://dawn-review.googlesource.com/c/dawn/+/225514
651+
PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/dawn/dawn.patch
650652
EXCLUDE_FROM_ALL
651653
)
652654
endif()
@@ -657,20 +659,6 @@ if (onnxruntime_USE_WEBGPU)
657659

658660
if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
659661
set(DAWN_EMSCRIPTEN_TOOLCHAIN "${REPO_ROOT}/cmake/external/emsdk/upstream/emscripten" CACHE STRING "" FORCE)
660-
661-
# Add the missing files from the emsdk installation
662-
#
663-
# For a "standard" emscripten build, the folder "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/" is not used. This is the
664-
# reason why EMSDK installation does not include it.
665-
# However, currently the WebGPU support in Emscripten is still being developed and the Dawn project is maintaining
666-
# a fork of the Emscripten toolchain. As an extra build step, Dawn needs to generate some files using the file
667-
# "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py" from emscripten, which is missing in the emscripten
668-
# installed by emsdk.
669-
#
670-
# We keep a copy of the missing file(s) in ${PROJECT_SOURCE_DIR}/patches/emscripten/, and now we extract them to the
671-
# emscripten toolchain folder.
672-
execute_process(COMMAND ${CMAKE_COMMAND} -E tar x "${PROJECT_SOURCE_DIR}/patches/emscripten/patch_3.1.74.tgz"
673-
WORKING_DIRECTORY ${DAWN_EMSCRIPTEN_TOOLCHAIN})
674662
else()
675663
if (onnxruntime_BUILD_DAWN_MONOLITHIC_LIBRARY)
676664
set(DAWN_BUILD_MONOLITHIC_LIBRARY ON CACHE BOOL "" FORCE)

cmake/onnxruntime_webassembly.cmake

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,4 +472,59 @@ jsepDownload:_pp_")
472472
endif()
473473

474474
set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME ${target_name} SUFFIX ".mjs")
475+
476+
#
477+
# The following POST_BUILD script is a workaround for enabling:
478+
# - using onnxruntime-web with Multi-threading enabled when import from CDN
479+
# - using onnxruntime-web when consumed in some frameworks like Vite
480+
#
481+
# In the use case mentioned above, the file name of the script may be changed. So we need to replace the line:
482+
# `new Worker(new URL("ort-wasm-*.mjs", import.meta.url),`
483+
# with
484+
# `new Worker(new URL(import.meta.url),`
485+
#
486+
# This behavior is introduced in https://github.com/emscripten-core/emscripten/pull/22165. Since it's unlikely to be
487+
# reverted, and there is no config to disable this behavior, we have to use a post-build script to workaround it.
488+
#
489+
490+
# Generate a script to do the post-build work
491+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/wasm_post_build.js "
492+
const fs = require('fs');
493+
const path = require('path');
494+
495+
// node wasm_post_build.js <mjsFilePath>
496+
const mjsFilePath = process.argv[2];
497+
let contents = fs.readFileSync(mjsFilePath).toString();
498+
499+
const regex = 'new Worker\\\\(new URL\\\\(\".+?\", ?import\\\\.meta\\\\.url\\\\),';
500+
const matches = [...contents.matchAll(new RegExp(regex, 'g'))];
501+
if (matches.length !== 1) {
502+
throw new Error(
503+
`Unexpected number of matches for \"${regex}\" in \"${filepath}\": ${matches.length}.`,
504+
);
505+
}
506+
507+
// Replace the only occurrence.
508+
contents = contents.replace(
509+
new RegExp(regex),
510+
`new Worker(new URL(import.meta.url),`,
511+
);
512+
513+
fs.writeFileSync(mjsFilePath, contents);
514+
"
515+
)
516+
517+
find_program(NODE_EXECUTABLE node required)
518+
if (NOT NODE_EXECUTABLE)
519+
message(FATAL_ERROR "Node is required to run the post-build script")
520+
endif()
521+
522+
add_custom_command(
523+
TARGET onnxruntime_webassembly
524+
POST_BUILD
525+
# Backup file at $<TARGET_FILE_NAME:onnxruntime_webassembly>.bak
526+
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE_NAME:onnxruntime_webassembly>" "$<TARGET_FILE_NAME:onnxruntime_webassembly>.bak"
527+
COMMAND ${CMAKE_COMMAND} -E echo "Performing post-process for $<TARGET_FILE_NAME:onnxruntime_webassembly>"
528+
COMMAND ${NODE_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/wasm_post_build.js" "$<TARGET_FILE_NAME:onnxruntime_webassembly>"
529+
)
475530
endif()

cmake/patches/dawn/dawn.patch

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
diff --git a/src/emdawnwebgpu/CMakeLists.txt b/src/emdawnwebgpu/CMakeLists.txt
2+
index 6e8ae37593..633af91eef 100644
3+
--- a/src/emdawnwebgpu/CMakeLists.txt
4+
+++ b/src/emdawnwebgpu/CMakeLists.txt
5+
@@ -77,9 +77,17 @@ if (${DAWN_ENABLE_EMSCRIPTEN})
6+
"${arg_UNPARSED_ARGUMENTS}")
7+
endif()
8+
9+
+ # since Emscripten 4.0.3, file gen_struct_info.py is moved to outside of directory maint.
10+
+ if (EXISTS "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/gen_struct_info.py")
11+
+ set(EM_GEN_STRUCT_INFO_SCRIPT "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/gen_struct_info.py")
12+
+ elseif (EXISTS "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py")
13+
+ set(EM_GEN_STRUCT_INFO_SCRIPT "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py")
14+
+ else()
15+
+ message(FATAL_ERROR "Dawn: Failed to locate file gen_struct_info.py from Emscripten.")
16+
+ endif()
17+
set(ARGS
18+
${Python3_EXECUTABLE}
19+
- "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py"
20+
+ "${EM_GEN_STRUCT_INFO_SCRIPT}"
21+
-q
22+
"${EM_BUILD_GEN_DIR}/struct_info_webgpu.json"
23+
"-I=${EM_BUILD_GEN_DIR}/include"
-4.55 KB
Binary file not shown.

tools/ci_build/build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ def convert_arg_line_to_args(self, arg_line):
488488
# WebAssembly build
489489
parser.add_argument("--build_wasm", action="store_true", help="Build for WebAssembly")
490490
parser.add_argument("--build_wasm_static_lib", action="store_true", help="Build for WebAssembly static library")
491-
parser.add_argument("--emsdk_version", default="3.1.59", help="Specify version of emsdk")
491+
parser.add_argument("--emsdk_version", default="4.0.3", help="Specify version of emsdk")
492492

493493
parser.add_argument("--enable_wasm_simd", action="store_true", help="Enable WebAssembly SIMD")
494494
parser.add_argument("--enable_wasm_threads", action="store_true", help="Enable WebAssembly multi-threads support")

tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
name: ${{ parameters.PoolName }}
4646
variables:
4747
buildArch: x64
48-
CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}'
48+
CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads ${{ parameters.ExtraBuildArgs }}'
4949
runCodesignValidationInjection: false
5050
TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)]
5151
ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache
@@ -82,15 +82,15 @@ jobs:
8282
- script: |
8383
set -ex
8484
cd '$(Build.SourcesDirectory)/cmake/external/emsdk'
85-
./emsdk install 3.1.59 ccache-git-emscripten-64bit
86-
./emsdk activate 3.1.59 ccache-git-emscripten-64bit
85+
./emsdk install 4.0.3 ccache-git-emscripten-64bit
86+
./emsdk activate 4.0.3 ccache-git-emscripten-64bit
8787
displayName: 'emsdk install and activate ccache for emscripten'
8888
- ${{if eq(parameters.WithCache, false)}}:
8989
- script: |
9090
set -ex
9191
cd '$(Build.SourcesDirectory)/cmake/external/emsdk'
92-
./emsdk install 3.1.59
93-
./emsdk activate 3.1.59
92+
./emsdk install 4.0.3
93+
./emsdk activate 4.0.3
9494
displayName: 'emsdk install and activate ccache for emscripten'
9595
9696
- template: build-linux-wasm-step.yml

0 commit comments

Comments
 (0)