diff --git a/package-lock.json b/package-lock.json index f30a4856013..84734983dc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@typescript-eslint/parser": "6.7.3", "arraybuffer-loader": "1.0.8", "babel-loader": "9.1.3", + "binaryen": "^116.0.0", "chai": "4.3.8", "core-js": "3.32.2", "esbuild": "0.19.3", @@ -4765,6 +4766,16 @@ "node": ">=8" } }, + "node_modules/binaryen": { + "version": "116.0.0", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-116.0.0.tgz", + "integrity": "sha512-Hp0dXC6Cb/rTwWEoUS2BRghObE7g/S9umKtxuTDt3f61G6fNTE/YVew/ezyy3IdHcLx3f17qfh6LwETgCfvWkQ==", + "dev": true, + "bin": { + "wasm-opt": "bin/wasm-opt", + "wasm2js": "bin/wasm2js" + } + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -18062,6 +18073,12 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "binaryen": { + "version": "116.0.0", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-116.0.0.tgz", + "integrity": "sha512-Hp0dXC6Cb/rTwWEoUS2BRghObE7g/S9umKtxuTDt3f61G6fNTE/YVew/ezyy3IdHcLx3f17qfh6LwETgCfvWkQ==", + "dev": true + }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", diff --git a/package.json b/package.json index c3b5703762f..4ac0c927567 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "build:all": "npm run build:rxp:all && npm run build:wasm:release", "build:rxp:all": "npm run bundle && npm run bundle:min && npm run build", "build:wasm:debug": "cd ./src/parsers/manifest/dash/wasm-parser && cargo build --target wasm32-unknown-unknown && cp target/wasm32-unknown-unknown/debug/mpd_node_parser.wasm ../../../../../dist/mpd-parser.wasm", - "build:wasm:release": "cd ./src/parsers/manifest/dash/wasm-parser && cargo build --target wasm32-unknown-unknown --release && wasm-opt -O3 -o ../../../../../dist/mpd-parser.wasm target/wasm32-unknown-unknown/release/mpd_node_parser.wasm && cd ../../../../../ && npm run wasm-strip", + "build:wasm:release": "cd ./src/parsers/manifest/dash/wasm-parser && cargo build --target wasm32-unknown-unknown --release && node ../../../../../scripts/wasm-optimize.mjs target/wasm32-unknown-unknown/release/mpd_node_parser.wasm ../../../../../dist/mpd-parser.wasm && cd ../../../../../ && npm run wasm-strip", "bundle": "webpack --progress --config webpack.config.mjs --env production", "bundle:min": "webpack --progress --config webpack.config.mjs --env minify --env production", "bundle:min:watch": "webpack --progress --config webpack.config.mjs -w --env production --env minify", @@ -185,6 +185,7 @@ "@typescript-eslint/parser": "6.7.3", "arraybuffer-loader": "1.0.8", "babel-loader": "9.1.3", + "binaryen": "116.0.0", "chai": "4.3.8", "core-js": "3.32.2", "esbuild": "0.19.3", diff --git a/scripts/wasm-optimize.mjs b/scripts/wasm-optimize.mjs new file mode 100644 index 00000000000..0a3216fe4f3 --- /dev/null +++ b/scripts/wasm-optimize.mjs @@ -0,0 +1,63 @@ +/** + * ============= wasm-optimize util ============= + * + * == What is this? + * + * This file allows to optimize a WebAssembly binary file (`.wasm`) by running + * binaryen's wasm-opt tool on it, through its JavaScript API. + * + * To run it, provide the source WebAssembly file as first argument and the + * output as second: + * ``` + * node wasm-optimize.mjs source.wasm dest.wasm + * ``` + * + * == Why? + * + * As the WebAssembly file produced by the RxPlayer is mostly for performance + * enhancement, it is important that we squeeze the most performance out of it + * at compile-time. + * + * The wasm-opt tool specically optimizes WebAssembly files, it is different + * from performance improvements made by the initial source compiler (e.g. the + * Rust compiler) which may not have the same constraints. Whether this script + * brings or not an improvement in comparison to the source WebAssembly file + * still should probably be regularly checked in real-life scenarios. + */ + +import binaryen from "binaryen"; +import * as fs from "fs"; + +run(); +function run() { + let inputFileName; + let outputFileName; + + if (process.argv.length < 3) { + console.error("Error: missing input file as first argument"); + process.exit(1); + } + if (process.argv.length < 4) { + console.error("Error: missing output file as second argument"); + process.exit(1); + } + inputFileName = process.argv[2]; + outputFileName = process.argv[3]; + + console.log("Starting logic to optimize wasm file:", inputFileName); + + let dataU8; + try { + const data = fs.readFileSync(inputFileName); + dataU8 = new Uint8Array(data.buffer); + binaryen.setOptimizeLevel(4); + const module = binaryen.readBinary(dataU8); + module.optimize(); + const output = module.emitBinary(); + fs.writeFileSync(outputFileName, output); + } catch (err) { + console.error("Error:", err?.message ?? "Unknown"); + process.exit(1); + } + console.log("WASM successfuly optimized!"); +} diff --git a/scripts/wasm-strip.mjs b/scripts/wasm-strip.mjs index 4a5632a0926..ed57d3a11dc 100644 --- a/scripts/wasm-strip.mjs +++ b/scripts/wasm-strip.mjs @@ -6,6 +6,12 @@ * This file allows to remove debugging information from a WebAssembly binary * file (`.wasm`). * + * To run it, provide the source WebAssembly file in argument, it will be + * updated in place: + * ``` + * node wasm-strip.mjs file_to_strip.wasm + * ``` + * * * == Why? * diff --git a/src/parsers/manifest/dash/wasm-parser/README.md b/src/parsers/manifest/dash/wasm-parser/README.md index 55d090e5101..74b781b3aff 100644 --- a/src/parsers/manifest/dash/wasm-parser/README.md +++ b/src/parsers/manifest/dash/wasm-parser/README.md @@ -246,22 +246,26 @@ On Rust-side, we exploit multiple FFI features: The Rust code is compiled through npm scripts, just like all other building logic in the RxPlayer. -To be able to call the corresponding npm script [1], you will need to: +The name of those scripts are not repeated in this document because of the +fear that they may change in the future, in which case this documentation could +easily be outdated. - 1. Install [cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html), - which is roughly Rust's npm. +To be able to call those scripts, you will need to have the Rust compiler +toolchain installed and ready to compile to WebAssembly. - 2. Install [binaryen](https://github.com/WebAssembly/binaryen), which is a - WebAssembly toolbox we're using to optimize the built wasm file. +To do this, the easiest way would be to rely on `rustup`, a tool to install and +update Rust toolchains: -If you see error messages while building related to a "wasm32-unknown-unknown" -target not being installed, you should install it. + 1. Install [rustup](https://rustup.rs/) -If you use `rustup` this can be done for example by writing: -```sh -rustup target add wasm32-unknown-unknown -``` + 2. Install and rely on the stable toolchain: + ```sh + rustup default stable + ``` -[1] The name of those scripts are not repeated in this document because of the -fear that they may change in the future, in which case this documentation could -easily be outdated. + 3. Add the WebAssembly compiler target: + ```sh + rustup target add wasm32-unknown-unknown + ``` + +That should be it!