From a85fe1088c717725370fa00f72d6d58c321445c9 Mon Sep 17 00:00:00 2001 From: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:20:05 -0800 Subject: [PATCH] Base commit for using EMSDK 3.1.74 (LTO disabled) --- .gitmodules | 2 +- cgmanifests/generated/cgmanifest.json | 2 +- cmake/CMakeLists.txt | 4 ++ cmake/adjust_global_compile_flags.cmake | 4 +- cmake/external/emsdk | 2 +- cmake/onnxruntime_config.h.in | 1 + cmake/onnxruntime_unittests.cmake | 8 --- cmake/onnxruntime_webassembly.cmake | 64 ++++++++++++++++++- include/onnxruntime/core/framework/float16.h | 8 +-- include/onnxruntime/core/framework/float8.h | 16 ++--- js/package-lock.json | 14 ++-- js/package.json | 2 +- js/web/script/build.ts | 42 +----------- .../src/components/onnx-helper.js | 7 +- tools/ci_build/build.py | 2 +- .../templates/linux-wasm-ci.yml | 8 +-- 16 files changed, 103 insertions(+), 83 deletions(-) diff --git a/.gitmodules b/.gitmodules index 29ca8821f8eb8..7b5be57db96bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,4 +7,4 @@ [submodule "cmake/external/emsdk"] path = cmake/external/emsdk url = https://github.com/emscripten-core/emsdk.git - branch = 3.1.59 + branch = 3.1.74 diff --git a/cgmanifests/generated/cgmanifest.json b/cgmanifests/generated/cgmanifest.json index ced418e0f4cc9..3576a9e12908c 100644 --- a/cgmanifests/generated/cgmanifest.json +++ b/cgmanifests/generated/cgmanifest.json @@ -6,7 +6,7 @@ "component": { "type": "git", "git": { - "commitHash": "d52c46520124845b1e0e0525f2759299d840143f", + "commitHash": "3d6d8ee910466516a53e665b86458faa81dae9ba", "repositoryUrl": "https://github.com/emscripten-core/emsdk.git" }, "comments": "git submodule at cmake/external/emsdk" diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index febefff6756e7..004b62c1b3e07 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -679,6 +679,7 @@ else() check_cxx_compiler_flag(-Wdeprecated-builtins HAS_DEPRECATED_BUILTINS) check_cxx_compiler_flag(-Wdeprecated-copy HAS_DEPRECATED_COPY) check_cxx_compiler_flag(-Wdeprecated-declarations HAS_DEPRECATED_DECLARATIONS) + check_cxx_compiler_flag(-Wdeprecated-literal-operator HAS_DEPRECATED_LITERAL_OPERATOR) check_cxx_compiler_flag(-Wdeprecated-this-capture HAS_DEPRECATED_THIS_CAPTURE) check_cxx_compiler_flag(-Wenum-constexpr-conversion HAS_ENUM_CONSTEXPR_CONVERSION) check_cxx_compiler_flag(-Wformat-truncation HAS_FORMAT_TRUNCATION) @@ -735,6 +736,9 @@ else() if (HAS_DEPRECATED_BUILTINS) list(APPEND ORT_WARNING_FLAGS -Wno-deprecated-builtins) endif() + if (HAS_DEPRECATED_LITERAL_OPERATOR) + list(APPEND ORT_WARNING_FLAGS -Wno-deprecated-literal-operator) + endif() #see:https://reviews.llvm.org/D131307 #It was intended that the 'enum-constexpr-conversion' type warnings can not be silenced by -w if(HAS_ENUM_CONSTEXPR_CONVERSION AND NOT Protobuf_FOUND) diff --git a/cmake/adjust_global_compile_flags.cmake b/cmake/adjust_global_compile_flags.cmake index 8325700b423f7..01b8a34b773fb 100644 --- a/cmake/adjust_global_compile_flags.cmake +++ b/cmake/adjust_global_compile_flags.cmake @@ -38,8 +38,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # (2) "-flto=thin" does not work correctly for wasm-ld. # we don't set onnxruntime_ENABLE_LTO because it appends flag "-flto=thin" # instead, we manually set CMAKE_CXX_FLAGS "-flto" - string(APPEND CMAKE_C_FLAGS " -flto") - string(APPEND CMAKE_CXX_FLAGS " -flto") + #string(APPEND CMAKE_C_FLAGS " -flto=thin") + #string(APPEND CMAKE_CXX_FLAGS " -flto=thin") endif() if (onnxruntime_ENABLE_WEBASSEMBLY_DEBUG_INFO) diff --git a/cmake/external/emsdk b/cmake/external/emsdk index d52c465201248..3d6d8ee910466 160000 --- a/cmake/external/emsdk +++ b/cmake/external/emsdk @@ -1 +1 @@ -Subproject commit d52c46520124845b1e0e0525f2759299d840143f +Subproject commit 3d6d8ee910466516a53e665b86458faa81dae9ba diff --git a/cmake/onnxruntime_config.h.in b/cmake/onnxruntime_config.h.in index bbddefe531cb8..f82a23bf4026b 100644 --- a/cmake/onnxruntime_config.h.in +++ b/cmake/onnxruntime_config.h.in @@ -9,6 +9,7 @@ #cmakedefine HAS_CLASS_MEMACCESS #cmakedefine HAS_DEPRECATED_COPY #cmakedefine HAS_DEPRECATED_DECLARATIONS +#cmakedefine HAS_DEPRECATED_LITERAL_OPERATOR #cmakedefine HAS_DEPRECATED_THIS_CAPTURE #cmakedefine HAS_FORMAT_TRUNCATION #cmakedefine HAS_IGNORED_ATTRIBUTES diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 9e3ab4d41f416..7c1b9ddc1548f 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -221,19 +221,11 @@ function(AddTest) ) else() set(TEST_NODE_FLAGS) - if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) - list(APPEND TEST_NODE_FLAGS "--experimental-wasm-threads") - endif() - if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) - list(APPEND TEST_NODE_FLAGS "--experimental-wasm-simd") - endif() # prefer Node from emsdk so the version is more deterministic if (DEFINED ENV{EMSDK_NODE}) set(NODE_EXECUTABLE $ENV{EMSDK_NODE}) else() - # warning as we don't know what node version is being used and whether things like the TEST_NODE_FLAGS - # will be valid. e.g. "--experimental-wasm-simd" is not valid with node v20 or later. message(WARNING "EMSDK_NODE environment variable was not set. Falling back to system `node`.") set(NODE_EXECUTABLE node) endif() diff --git a/cmake/onnxruntime_webassembly.cmake b/cmake/onnxruntime_webassembly.cmake index 66268cefac9ef..61e945de9b45a 100644 --- a/cmake/onnxruntime_webassembly.cmake +++ b/cmake/onnxruntime_webassembly.cmake @@ -380,10 +380,15 @@ jsepDownload:_pp_") "SHELL:--pre-js \"${ONNXRUNTIME_ROOT}/wasm/pre-jsep.js\"" "SHELL:-s ASYNCIFY=1" "SHELL:-s ASYNCIFY_STACK_SIZE=65536" - "SHELL:-s ASYNCIFY_EXPORTS=['OrtRun']" - "SHELL:-s ASYNCIFY_IMPORTS=['Module.jsepCopy','Module.jsepCopyAsync','jsepDownload']" ) set_target_properties(onnxruntime_webassembly PROPERTIES LINK_DEPENDS ${ONNXRUNTIME_ROOT}/wasm/pre-jsep.js) + + if (onnxruntime_ENABLE_WEBASSEMBLY_MEMORY64) + target_link_options(onnxruntime_webassembly PRIVATE + "SHELL:-s ASYNCIFY_EXPORTS=['OrtRun']" + "SHELL:-s ASYNCIFY_IMPORTS=['Module.jsepCopy','Module.jsepCopyAsync','jsepDownload']" + ) + endif() endif() if (onnxruntime_EMSCRIPTEN_SETTINGS) @@ -461,4 +466,59 @@ jsepDownload:_pp_") endif() set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME ${target_name} SUFFIX ".mjs") + + # + # The following POST_BUILD script is a workaround for enabling: + # - using onnxruntime-web with Multi-threading enabled when import from CDN + # - using onnxruntime-web when consumed in some frameworks like Vite + # + # In the use case mentioned above, the file name of the script may be changed. So we need to replace the line: + # `new Worker(new URL("ort-wasm-*.mjs", import.meta.url),` + # with + # `new Worker(new URL(import.meta.url),` + # + # This behavior is introduced in https://github.com/emscripten-core/emscripten/pull/22165. Since it's unlikely to be + # reverted, and there is no config to disable this behavior, we have to use a post-build script to workaround it. + # + + # Generate a script to do the post-build work + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/wasm_post_build.js " + const fs = require('fs'); + const path = require('path'); + + // node wasm_post_build.js + const mjsFilePath = process.argv[2]; + let contents = fs.readFileSync(mjsFilePath).toString(); + + const regex = 'new Worker\\\\(new URL\\\\(\".+?\", ?import\\\\.meta\\\\.url\\\\),'; + const matches = [...contents.matchAll(new RegExp(regex, 'g'))]; + if (matches.length !== 1) { + throw new Error( + `Unexpected number of matches for \"${regex}\" in \"${filepath}\": ${matches.length}.`, + ); + } + + // Replace the only occurrence. + contents = contents.replace( + new RegExp(regex), + `new Worker(new URL(import.meta.url),`, + ); + + fs.writeFileSync(mjsFilePath, contents); + " + ) + + find_program(NODE_EXECUTABLE node required) + if (NOT NODE_EXECUTABLE) + message(FATAL_ERROR "Node is required to run the post-build script") + endif() + + add_custom_command( + TARGET onnxruntime_webassembly + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Backup file at $.bak" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$.bak" + COMMAND ${CMAKE_COMMAND} -E echo "Performing workaround for $" + COMMAND ${NODE_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/wasm_post_build.js" "$" + ) endif() diff --git a/include/onnxruntime/core/framework/float16.h b/include/onnxruntime/core/framework/float16.h index dac0a01fbc3fe..97420ffe438d1 100644 --- a/include/onnxruntime/core/framework/float16.h +++ b/include/onnxruntime/core/framework/float16.h @@ -261,19 +261,19 @@ struct BFloat16 : onnxruntime_float16::BFloat16Impl { // initializers with MLFloat16 and BFloat16 from unsigned short // E.g 10_f16 or 10_b16 #if !defined(__CUDACC__) && !defined(__HIPCC__) -inline MLFloat16 operator"" _f16(unsigned long long int v) noexcept { +inline MLFloat16 operator""_f16(unsigned long long int v) noexcept { return MLFloat16::FromBits(narrow(v)); } -inline MLFloat16 operator"" _fp16(long double v) noexcept { +inline MLFloat16 operator""_fp16(long double v) noexcept { return MLFloat16(static_cast(v)); } -inline BFloat16 operator"" _b16(unsigned long long int v) noexcept { +inline BFloat16 operator""_b16(unsigned long long int v) noexcept { return BFloat16::FromBits((narrow(v))); } -inline BFloat16 operator"" _bfp16(long double v) noexcept { +inline BFloat16 operator""_bfp16(long double v) noexcept { return BFloat16(static_cast(v)); } #endif diff --git a/include/onnxruntime/core/framework/float8.h b/include/onnxruntime/core/framework/float8.h index 5d92ee86af864..9e94cc297f782 100644 --- a/include/onnxruntime/core/framework/float8.h +++ b/include/onnxruntime/core/framework/float8.h @@ -165,11 +165,11 @@ inline ORT_HOST_DEVICE bool operator<(const Float8E4M3FN& left, const Float8E4M3 // initializers with MLFloat8E4M3FN and Float8E4M3FN from unsigned char #if !defined(__CUDACC__) && !defined(__HIPCC__) -inline Float8E4M3FN operator"" _f8e4m3fn(unsigned long long int v) { +inline Float8E4M3FN operator""_f8e4m3fn(unsigned long long int v) { return Float8E4M3FN(narrow(v), Float8E4M3FN::FromBits()); } -inline Float8E4M3FN operator"" _f8e4m3fnp8(long double v) { +inline Float8E4M3FN operator""_f8e4m3fnp8(long double v) { return Float8E4M3FN(static_cast(v), true); } @@ -323,11 +323,11 @@ inline ORT_HOST_DEVICE bool operator<(const Float8E4M3FNUZ& left, const Float8E4 // initializers with MLFloat8E4M3FN and Float8E4M3FN from unsigned char #if !defined(__CUDACC__) && !defined(__HIPCC__) -inline Float8E4M3FNUZ operator"" _f8e4m3p8fnuz(unsigned long long int v) { +inline Float8E4M3FNUZ operator""_f8e4m3p8fnuz(unsigned long long int v) { return Float8E4M3FNUZ(narrow(v), Float8E4M3FNUZ::FromBits()); } -inline Float8E4M3FNUZ operator"" _f8e4m3fnuzp8(long double v) { +inline Float8E4M3FNUZ operator""_f8e4m3fnuzp8(long double v) { return Float8E4M3FNUZ(static_cast(v), true); } @@ -493,11 +493,11 @@ inline ORT_HOST_DEVICE bool operator<(const Float8E5M2& left, const Float8E5M2& // initializers with MLFloat8E5M2 and Float8E5M2 from unsigned char #if !defined(__CUDACC__) && !defined(__HIPCC__) -inline Float8E5M2 operator"" _f8e5m2fn(unsigned long long int v) { +inline Float8E5M2 operator""_f8e5m2fn(unsigned long long int v) { return Float8E5M2(narrow(v), Float8E5M2::FromBits()); } -inline Float8E5M2 operator"" _f8e5m2fnp8(long double v) { +inline Float8E5M2 operator""_f8e5m2fnp8(long double v) { return Float8E5M2(static_cast(v), true); } @@ -642,11 +642,11 @@ inline ORT_HOST_DEVICE bool operator<(const Float8E5M2FNUZ& left, const Float8E5 // initializers with MLFloat8E5M2 and Float8E5M2 from unsigned char #if !defined(__CUDACC__) && !defined(__HIPCC__) -inline Float8E5M2FNUZ operator"" _f8e5m2fnuz(unsigned long long int v) { +inline Float8E5M2FNUZ operator""_f8e5m2fnuz(unsigned long long int v) { return Float8E5M2FNUZ(narrow(v), Float8E5M2FNUZ::FromBits()); } -inline Float8E5M2FNUZ operator"" _f8e5m2fnuzp8(long double v) { +inline Float8E5M2FNUZ operator""_f8e5m2fnuzp8(long double v) { return Float8E5M2FNUZ(static_cast(v), true); } diff --git a/js/package-lock.json b/js/package-lock.json index 92eb0b422c76b..e915c001655d1 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -29,7 +29,7 @@ "mocha": "^11.0.1", "npmlog": "^7.0.1", "prettier": "^3.3.3", - "terser": "^5.31.0", + "terser": "^5.37.0", "typescript": "^5.2.2" } }, @@ -4783,9 +4783,9 @@ } }, "node_modules/terser": { - "version": "5.31.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", - "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -8518,9 +8518,9 @@ "dev": true }, "terser": { - "version": "5.31.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", - "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.3", diff --git a/js/package.json b/js/package.json index 3b7a3ec6e0a33..15cbe12e2742f 100644 --- a/js/package.json +++ b/js/package.json @@ -23,7 +23,7 @@ "mocha": "^11.0.1", "npmlog": "^7.0.1", "prettier": "^3.3.3", - "terser": "^5.31.0", + "terser": "^5.37.0", "typescript": "^5.2.2" }, "scripts": { diff --git a/js/web/script/build.ts b/js/web/script/build.ts index 6e8c3f0df8192..6006de62b41b6 100644 --- a/js/web/script/build.ts +++ b/js/web/script/build.ts @@ -145,51 +145,15 @@ async function minifyWasmModuleJsForBrowser(filepath: string): Promise { `new Worker(import.meta.url.startsWith('file:')?new URL(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url):new URL(import.meta.url),`, ); - // Find the first and the only occurrence of minified function implementation of "_emscripten_thread_set_strongref": - // ```js - // _emscripten_thread_set_strongref: (thread) => { - // if (ENVIRONMENT_IS_NODE) { - // PThread.pthreads[thread].ref(); - // } - // } - // ``` - // - // It is minified to: (example) - // ```js - // function Pb(a){D&&N[a>>>0].ref()} - // ``` - - // The following code will look for the function name and mark the function call as pure, so that Terser will - // minify the code correctly. - - const markedAsPure = []; - // First, try if we are working on the original (not minified) source file. This is when we are working with the - // debug build. - const isOriginal = contents.includes('PThread.pthreads[thread].ref()'); - if (isOriginal) { - markedAsPure.push('PThread.pthreads[thread].ref'); - } else { - // If it is not the original source file, we need to find the minified function call. - const matches = [...contents.matchAll(/\{[_a-zA-Z][_a-zA-Z0-9]*&&([_a-zA-Z][_a-zA-Z0-9]*\[.+?]\.ref)\(\)}/g)]; - if (matches.length !== 1) { - throw new Error( - `Unexpected number of matches for minified "PThread.pthreads[thread].ref()" in "${filepath}": ${ - matches.length - }.`, - ); - } - // matches[0] is the first and the only match. - // matches[0][0] is the full matched string and matches[0][1] is the first capturing group. - markedAsPure.push(matches[0][1]); - } - + // Use terser to minify the code with special configurations: + // - use `global_defs` to define `process` and `globalThis.process` as `undefined`, so terser can tree-shake the + // Node.js specific code. const terser = await import('terser'); const result = await terser.minify(contents, { module: true, compress: { passes: 2, global_defs: { process: undefined, 'globalThis.process': undefined }, - pure_funcs: markedAsPure, }, }); diff --git a/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js b/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js index f6b458ce55683..bbe57033a3cb7 100644 --- a/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js +++ b/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js @@ -1,14 +1,13 @@ import * as ort from 'onnxruntime-web'; -// The following line uses Vite's "Explicit URL Imports" feature to load the wasm files as asset. +// The following line uses Vite's "Explicit URL Imports" feature to load the wasm file as asset. // // see https://vite.dev/guide/assets.html#explicit-url-imports // import wasmFileUrl from '/node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.wasm?url'; -import mjsFileUrl from '/node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.mjs?url'; -// wasmFileUrl is a string that contains the URL of the wasm file. -ort.env.wasm.wasmPaths = { wasm: wasmFileUrl, mjs: mjsFileUrl }; +// wasmFileUrl is the URL of the wasm file. Vite will make sure it's available in both development and production. +ort.env.wasm.wasmPaths = { wasm: wasmFileUrl }; // Model data for "test_abs/model.onnx" const testModelData = diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index ed5efac274df0..318396aa71da0 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -478,7 +478,7 @@ def convert_arg_line_to_args(self, arg_line): # WebAssembly build parser.add_argument("--build_wasm", action="store_true", help="Build for WebAssembly") parser.add_argument("--build_wasm_static_lib", action="store_true", help="Build for WebAssembly static library") - parser.add_argument("--emsdk_version", default="3.1.59", help="Specify version of emsdk") + parser.add_argument("--emsdk_version", default="3.1.74", help="Specify version of emsdk") parser.add_argument("--enable_wasm_simd", action="store_true", help="Enable WebAssembly SIMD") parser.add_argument("--enable_wasm_threads", action="store_true", help="Enable WebAssembly multi-threads support") diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml index 3ab1cd45ff5f7..29eb322cc4812 100644 --- a/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml @@ -86,15 +86,15 @@ jobs: - script: | set -ex cd '$(Build.SourcesDirectory)/cmake/external/emsdk' - ./emsdk install 3.1.59 ccache-git-emscripten-64bit - ./emsdk activate 3.1.59 ccache-git-emscripten-64bit + ./emsdk install 3.1.74 ccache-git-emscripten-64bit + ./emsdk activate 3.1.74 ccache-git-emscripten-64bit displayName: 'emsdk install and activate ccache for emscripten' - ${{if eq(parameters.WithCache, false)}}: - script: | set -ex cd '$(Build.SourcesDirectory)/cmake/external/emsdk' - ./emsdk install 3.1.59 - ./emsdk activate 3.1.59 + ./emsdk install 3.1.74 + ./emsdk activate 3.1.74 displayName: 'emsdk install and activate ccache for emscripten' - template: build-linux-wasm-step.yml