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

Rust build image optimizations #1054

Merged
merged 5 commits into from
Jul 21, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,17 @@ WORKDIR /linked-packages
COPY {{dir}} ./{{name}}
{{/polywrap_linked_packages}}

WORKDIR /
RUN USER=root cargo new --lib project
WORKDIR /project

# Copy all manifest files
{{#polywrap_manifests}}
COPY {{.}} .
{{/polywrap_manifests}}

# Copy all source files
{{#include}}
COPY {{.}} {{.}}
{{/include}}
{{#polywrap_module}}
COPY {{dir}} {{dir}}
{{/polywrap_module}}
# Copy Cargo manifest files
COPY ./{{dir}}/Cargo.toml ./{{dir}}/Cargo.toml

{{#polywrap_linked_packages.length}}
# Link any local packages
Expand All @@ -58,15 +55,10 @@ RUN PACKAGE_NAME={{name}}; \
{{/polywrap_module}}
true
{{/polywrap_linked_packages}}

{{/polywrap_linked_packages.length}}

{{#polywrap_module}}
# Remove any Cargo.lock files
RUN rm -rf {{dir}}/Cargo.lock

# Ensure the Wasm module is configured to use imported memory
ENV RUSTFLAGS="-C link-arg=-z -C link-arg=stack-size=65536 -C link-arg=--import-memory"
# Mock build for dependencies:

# Ensure the module at {{dir}} has the crate-type = ["cdylib"]
RUN toml set ./{{dir}}/Cargo.toml lib.crate-type ["cdylib"] > ./{{dir}}/Cargo-local.toml && \
Expand All @@ -83,14 +75,29 @@ RUN toml set ./{{dir}}/Cargo.toml package.name "module" > ./{{dir}}/Cargo-local.
mv ./{{dir}}/Cargo-local.toml ./{{dir}}/Cargo.toml && \
true

# Make the build directory
RUN rm -rf ./build
RUN mkdir ./build
RUN cargo build --manifest-path ./{{dir}}/Cargo.toml --release

# Copy all source files
{{#include}}
COPY {{.}} {{.}}
{{/include}}
RUN mv ./{{dir}}/Cargo.toml ./{{dir}}/Cargo-deps.toml
COPY {{dir}} {{dir}}
RUN mv ./{{dir}}/Cargo-deps.toml ./{{dir}}/Cargo.toml && rm ./target/release/deps/module*

# Actual build:

# Ensure the Wasm module is configured to use imported memory
ENV RUSTFLAGS="-C link-arg=-z -C link-arg=stack-size=65536 -C link-arg=--import-memory"

# Build the module at {{dir}}
RUN cargo build --manifest-path ./{{dir}}/Cargo.toml \
--target wasm32-unknown-unknown --release

# Make the build directory
RUN rm -rf ./build
RUN mkdir ./build

# Enable the "WASM_INTERFACE_TYPES" feature, which will remove the __wbindgen_throw import.
# See: https://github.com/rustwasm/wasm-bindgen/blob/7f4663b70bd492278bf0e7bba4eeddb3d840c868/crates/cli-support/src/lib.rs#L397-L403
ENV WASM_INTERFACE_TYPES=1
Expand Down
97 changes: 97 additions & 0 deletions packages/js/client/src/__tests__/e2e/wasm-rs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
PolywrapClientConfig,
createPolywrapClient,
PolywrapClient,
} from "../..";
import * as TestCases from "./test-cases";
import { makeMemoryStoragePlugin } from "./memory-storage";
Expand All @@ -12,6 +13,10 @@ import {
providers
} from "@polywrap/test-env-js";
import { GetPathToTestWrappers } from "@polywrap/test-cases";
import fse from "fs-extra";
import path from "path";
import { execSync } from "child_process";
const { performance } = require("perf_hooks");

jest.setTimeout(1200000);

Expand Down Expand Up @@ -330,3 +335,95 @@ describe("wasm-rs test cases", () => {
);
})
});

describe.skip("Wasm-rs benchmarking", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

We can merge this as skipped for now, but we should probably make a benchmarking project that does this in the near future.

const wrapperPath = `${GetPathToTestWrappers()}/wasm-rs/benchmarks`
const wrapperUri = `fs/${wrapperPath}/build`

let cacheFiles = new Map<string, string>();
const mockFunc = `
fn froo() -> &'static str {
"foo"
}
`;

const modifySource = () => {
const libPath = path.join(wrapperPath, "src", "lib.rs");
const libFile = fse.readFileSync(libPath, "utf-8");

cacheFiles.set(libPath, libFile);

const modifiedFile = `${libFile}\n${mockFunc}`;

fse.writeFileSync(libPath, modifiedFile);
};

const buildImage = async (name: "current" | "new"): Promise<number> => {
const startTime = performance.now();

await buildWrapper(
wrapperPath,
name === "current"? "./polywrap-current.yaml": "./polywrap.yaml"
);

const endTime = performance.now();
const msTime = endTime - startTime;

//Make sure the wrapper works correctly
await TestCases.runBigNumberTypeTest(
new PolywrapClient(), wrapperUri
);

return msTime
};

beforeEach(() => {
fse.removeSync(`${wrapperPath}/build`);
fse.removeSync(`${wrapperPath}/.polywrap`);
});

const restoreSource = () => {
for (const [key, value] of cacheFiles) {
fse.writeFileSync(key, value);
}
};

it("Build image performance", async () => {
//Delete cached images and containers
execSync(`docker system prune -a -f`);

//Build the wrapper with no previously cached images
const firstBuildTimeNew = await buildImage("new");
console.log(`1st build - no cache (new): ${firstBuildTimeNew.toFixed(2)}ms`);

//Build the wrapper again
const secondBuildTimeNew = await buildImage("new");
console.log(`2nd build - with cache (new): ${secondBuildTimeNew.toFixed(2)}ms`);

//Modify the source code and measure build time
modifySource();

const timeAfterSourceNew = await buildImage("new",);
console.log(`3rd build - modified source (new): ${timeAfterSourceNew.toFixed(2)}ms`);

restoreSource();

// Repeat the process for current image and compare
execSync(`docker system prune -a -f`);

const firstBuildTimeCurrent = await buildImage("current");
console.log(`1st build - no cache (current): ${firstBuildTimeCurrent.toFixed(2)}ms`);

const secondBuildTimeCurrent = await buildImage("current");
console.log(`2nd build - with cache (current): ${secondBuildTimeCurrent.toFixed(2)}ms`);

modifySource();

const timeAfterSourceCurrent = await buildImage("current");
console.log(`3rd build - modified source (current): ${timeAfterSourceCurrent.toFixed(2)}ms`);

restoreSource();

expect(timeAfterSourceNew).toBeLessThan(timeAfterSourceCurrent);
})
})
9 changes: 7 additions & 2 deletions packages/js/test-env/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,13 @@ export const runCLI = async (options: {
};
};

export async function buildWrapper(wrapperAbsPath: string): Promise<void> {
const manifestPath = `${wrapperAbsPath}/polywrap.yaml`;
export async function buildWrapper(
wrapperAbsPath: string,
manifestPathOverride?: string
): Promise<void> {
const manifestPath = manifestPathOverride
? path.join(wrapperAbsPath, manifestPathOverride)
: `${wrapperAbsPath}/polywrap.yaml`;
const {
exitCode: buildExitCode,
stdout: buildStdout,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
FROM rust:1.60.0 as base

# Install the wasm32 rust build target
RUN rustup target add wasm32-unknown-unknown

WORKDIR /build-deps

# Install curl
RUN apt-get update
RUN apt-get -y install curl clang llvm build-essential

# Install wasm-opt
RUN curl -L https://github.com/WebAssembly/binaryen/releases/download/version_101/binaryen-version_101-x86_64-linux.tar.gz | tar -xz \
&& chmod +x binaryen-version_101/bin/wasm-opt \
&& cp binaryen-version_101/bin/wasm-opt /usr/local/bin/ \
&& rm -rf binary-version_101

# Install the toml-cli
RUN cargo install -f toml-cli

# Install wasm-snip
RUN cargo install -f wasm-snip

# Install wasm-bindgen
RUN cargo install -f wasm-bindgen-cli

WORKDIR /project

# Copy all manifest files
COPY polywrap.yaml .
COPY polywrap.build.yaml .

# Copy all source files
COPY ./Cargo.toml ./Cargo.toml
COPY ./src ./src
COPY ./schema.graphql ./schema.graphql
COPY ./plugin.schema.graphql ./plugin.schema.graphql

# Remove any Cargo.lock files
RUN rm -rf ./Cargo.lock

# Ensure the Wasm module is configured to use imported memory
ENV RUSTFLAGS="-C link-arg=-z -C link-arg=stack-size=65536 -C link-arg=--import-memory"

# Ensure the module at . has the crate-type = ["cdylib"]
RUN toml set ././Cargo.toml lib.crate-type ["cdylib"] > ././Cargo-local.toml && \
rm -rf ././Cargo.toml && \
mv ././Cargo-local.toml ././Cargo.toml && \
true

# Clean up artifacts left by the toml CLI program ("["cdylib"]" -> ["cdylib"])
RUN sed -i 's/"\[cdylib\]"/\["cdylib"\]/g' ././Cargo.toml

# Ensure the package name = "module"
RUN toml set ././Cargo.toml package.name "module" > ././Cargo-local.toml && \
rm -rf ././Cargo.toml && \
mv ././Cargo-local.toml ././Cargo.toml && \
true

# Make the build directory
RUN rm -rf ./build
RUN mkdir ./build

# Build the module at .
RUN cargo build --manifest-path ././Cargo.toml \
--target wasm32-unknown-unknown --release

# Enable the "WASM_INTERFACE_TYPES" feature, which will remove the __wbindgen_throw import.
# See: https://github.com/rustwasm/wasm-bindgen/blob/7f4663b70bd492278bf0e7bba4eeddb3d840c868/crates/cli-support/src/lib.rs#L397-L403
ENV WASM_INTERFACE_TYPES=1

# Run wasm-bindgen over the module, replacing all placeholder __wbindgen_... imports
RUN wasm-bindgen ././target/wasm32-unknown-unknown/release/module.wasm --out-dir ./build --out-name bg_module.wasm

RUN wasm-snip ./build/bg_module.wasm -o ./build/snipped_module.wasm && \
rm -rf ./build/bg_module.wasm

# Use wasm-opt to perform the "asyncify" post-processing step over all modules
RUN wasm-opt --asyncify -Os ./build/snipped_module.wasm -o ./build/wrap.wasm && \
rm -rf ./build/snipped_module.wasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "module"
version = "0.1.0"
description = "Query module of bigint-type e2e test"
authors = [
"Kobby Pentangeli <kobbypentangeli@gmail.com>",
"Jordan Ellis <jelli@dorg.tech>"
]
repository = "https://github.com/polywrap/monorepo"
license = "MIT"
edition = "2021"

[dependencies]
polywrap-wasm-rs = { path = "../../../../../../wasm/rs" }
serde = { version = "1.0", features = ["derive"] }
ethers = "0.14.0"

[lib]
crate-type = ["cdylib"]

[profile.release]
opt-level = 's'
lto = true
panic = 'abort'
Loading