Skip to content

Commit

Permalink
feat(query-engine-wasm): twiggy-related utilities (#4569)
Browse files Browse the repository at this point in the history
* feat(query-engine-wasm): move wasm-opt options from Cargo.toml to build.sh, to share subset of it between multiple build profiles

* feat(query-engine-wasm): add wasm-inspect.sh to analyse human-friendly WebAssembly code (*.wat)

* chore: fix shellcheck SC2155

* feat(query-engine-wasm): default to "dev" profile; one can still opt in for WASM_BUILD_PROFILE="profiling"

* feat(query-engine-wasm): update README.md
  • Loading branch information
jkomyno authored Dec 18, 2023
1 parent 2592cb6 commit c16f468
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 12 deletions.
16 changes: 4 additions & 12 deletions query-engine/query-engine-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,7 @@ tracing-opentelemetry = "0.17.3"
opentelemetry = { version = "0.17"}

[package.metadata.wasm-pack.profile.release]
wasm-opt = [
"-O", # execute default optimization passes
"--vacuum", # removes obviously unneeded code
"--duplicate-function-elimination", # removes duplicate functions
"--duplicate-import-elimination", # removes duplicate imports
"--remove-unused-module-elements", # removes unused module elements
"--dae-optimizing", # removes arguments to calls in an lto-like manner
"--remove-unused-names", # removes names from location that are never branched to
"--rse", # removes redundant local.sets
"--gsi", # global struct inference, to optimize constant values
"--gufa-optimizing", # optimize the entire program using type monomorphization
]
wasm-opt = false # use wasm-opt explicitly in `./build.sh`

[package.metadata.wasm-pack.profile.profiling]
wasm-opt = false # use wasm-opt explicitly in `./build.sh`
11 changes: 11 additions & 0 deletions query-engine/query-engine-wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ From the current folder:
- `./build.sh $OUT_NPM_VERSION`

where e.g. `OUT_NPM_VERSION="0.0.1"` is the version you want to publish this package on npm with.
By default, the build profile is `dev` in local builds, and `release` in CI builds.
You can override this by setting the `WASM_BUILD_PROFILE` environment variable.
E.g., `WASM_BUILD_PROFILE="profiling"` is useful for interoperating with the `twiggy` size profiler.

See [`./build.sh`](./build.sh) for more details.

## How to Publish

Expand All @@ -38,3 +43,9 @@ To try importing the , you can run:

- `nvm use`
- `node --experimental-wasm-modules example/example.js`

## How to analyse the size of the Wasm binary

- Build the Wasm binary with `WASM_BUILD_PROFILE="profiling" ./build.sh "0.0.1"`
- Run `twiggy top -n 20 ./pkg/query_engine_bg.wasm`
- Take a look at this [Notion document](https://www.notion.so/prismaio/Edge-Functions-how-to-use-twiggy-and-other-size-tracking-tools-c1cb481cbd0c4a0488f6876674988382) for more details, and for instructions on how to refine `twiggy`'s output via [`./wasm-inspect.sh`](./wasm-inspect.sh).
46 changes: 46 additions & 0 deletions query-engine/query-engine-wasm/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ if [[ -z "${WASM_BUILD_PROFILE:-}" ]]; then
fi
fi

echo "Using build profile: \"${WASM_BUILD_PROFILE}\""

# Check if wasm-pack is installed
if ! command -v wasm-pack &> /dev/null
then
Expand All @@ -29,6 +31,50 @@ fi

wasm-pack build "--$WASM_BUILD_PROFILE" --target $OUT_TARGET --out-name query_engine

WASM_OPT_ARGS=(
"-Os" # execute size-focused optimization passes
"--vacuum" # removes obviously unneeded code
"--duplicate-function-elimination" # removes duplicate functions
"--duplicate-import-elimination" # removes duplicate imports
"--remove-unused-module-elements" # removes unused module elements
"--dae-optimizing" # removes arguments to calls in an lto-like manner
"--remove-unused-names" # removes names from location that are never branched to
"--rse" # removes redundant local.sets
"--gsi" # global struct inference, to optimize constant values
"--gufa-optimizing" # optimize the entire program using type monomorphization
"--strip-dwarf" # removes DWARF debug information
"--strip-producers" # removes the "producers" section
"--strip-target-features" # removes the "target_features" section
)

case "$WASM_BUILD_PROFILE" in
release)
# In release mode, we want to strip the debug symbols.
wasm-opt "${WASM_OPT_ARGS[@]}" \
"--strip-debug" \
"${OUT_FOLDER}/query_engine_bg.wasm" \
-o "${OUT_FOLDER}/query_engine_bg.wasm"
;;
profiling)
# In profiling mode, we want to keep the debug symbols.
wasm-opt "${WASM_OPT_ARGS[@]}" \
"--debuginfo" \
"${OUT_FOLDER}/query_engine_bg.wasm" \
-o "${OUT_FOLDER}/query_engine_bg.wasm"
;;
*)
# In other modes (e.g., "dev"), skip wasm-opt.
echo "Skipping wasm-opt."
;;
esac

# Convert the `.wasm` file to its human-friendly `.wat` representation for debugging purposes, if `wasm2wat` is installed
if ! command -v wasm2wat &> /dev/null; then
echo "Skipping wasm2wat, as it is not installed."
else
wasm2wat "${OUT_FOLDER}/query_engine_bg.wasm" -o "./query_engine.wat"
fi

sleep 1

# Mark the package as a ES module, set the entry point to the query_engine.js file, mark the package as public
Expand Down
107 changes: 107 additions & 0 deletions query-engine/query-engine-wasm/wasm-inspect.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/bin/bash

# Call this script as `./wasm-inpect.sh`
set -euo pipefail

wat_file="./query_engine.wat"

# Check if the .wat file exists
if [ ! -f "$wat_file" ]; then
echo "Error: $wat_file not found."
exit 1
fi

USE_LINK=false
for arg in "$@"; do
if [ "$arg" == "--link" ]; then
USE_LINK=true
break
fi
done

# Inspect the specified function name in the .wat file.
# Use as `func <function_name> [--link]`.
inspect_function() {
local function_name="$1"

# Use sed to find the line number where the function starts
local -r start_line=$(sed -n "/(func \$$function_name/=" "$wat_file" | head -n 1)

# Check if the function exists in the file
if [ -z "$start_line" ]; then
echo "Error: Function '$function_name' not found in '$wat_file'."
exit 1
fi

__display_wat
}

# Inspect the specified data entry in the .wat file.
# Use as `data <data_entry> [--link]`.
inspect_data() {
local data_entry="$1"

# Use sed to find the line number where the data entry starts
# (data (;139;)
local -r start_line=$(sed -n "/(data (;$data_entry;)/=" "$wat_file" | head -n 1)

# Check if the function exists in the file
if [ -z "$start_line" ]; then
echo "Error: Data entry '$data_entry' not found in '$wat_file'."
exit 1
fi

__display_wat
}

__display_wat() {
if [ "$USE_LINK" == true ]; then
# --link option is used, so print the link to the function location
local -r file_path=$(realpath "$wat_file")
local vscode_link="$file_path:$start_line"
echo -e "$vscode_link"
else
# print the function definition, and allow the user to scroll through it
less -N "+${start_line}" "$wat_file"
fi
}

# Function to display help message
display_help() {

local HELP_MESSAGE="
Usage: $0 <command> <function_name> [--link]
Inspect the specified function in the .wat file.
Commands:
func <name> Inspect the specified function
data <entry> Inspect the specified data entry
Options:
--link Show a link to the wat code rather than printing
the definition to stdout
--help Display this help message
"
echo -e "$HELP_MESSAGE"
}

# Parse the command and execute the corresponding action
case "$1" in
func)
shift
inspect_function "$@"
;;
data)
shift
inspect_data "$@"
;;
--help)
display_help
;;
*)
echo "Unknown command: $1"
exit 1
;;
esac

exit 0

0 comments on commit c16f468

Please sign in to comment.