From 3987fa5a23bdc21c1abae52a387f0ca224e93197 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Feb 2020 09:55:31 +0000 Subject: [PATCH 1/6] Optimize wasm with Binaryen wasm-opt --- Cargo.lock | 11 ++++++++++ Cargo.toml | 1 + src/cmd/build.rs | 54 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c20d389..875f2235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,6 +284,7 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2952,6 +2953,15 @@ dependencies = [ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "which" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -3350,6 +3360,7 @@ dependencies = [ "checksum webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e664e770ac0110e2384769bcc59ed19e329d81f555916a6e072714957b81b4" "checksum webpki-roots 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b" "checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" +"checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 3cee7d43..88a6be71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ pwasm-utils = "0.12" parity-wasm = "0.41" cargo_metadata = "0.9" codec = { package = "parity-scale-codec", version = "1.1" } +which = "3.1.0" # dependencies for optional extrinsics feature async-std = { version = "1.2.0", optional = true } diff --git a/src/cmd/build.rs b/src/cmd/build.rs index b7deddfb..d527b999 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -14,7 +14,11 @@ // You should have received a copy of the GNU General Public License // along with ink!. If not, see . -use std::path::PathBuf; +use std::{ + io::{self, Write}, + path::PathBuf, + process::Command, +}; use anyhow::{Context, Result}; use cargo_metadata::MetadataCommand; @@ -25,6 +29,7 @@ const MAX_MEMORY_PAGES: u32 = 16; /// Relevant metadata obtained from Cargo.toml. pub struct CrateMetadata { + package_name: String, original_wasm: PathBuf, pub dest_wasm: PathBuf, } @@ -62,10 +67,11 @@ pub fn collect_crate_metadata(working_dir: Option<&PathBuf>) -> Result Result<()> { Ok(()) } +/// Attempts to perform optional wasm optimization using `wasm-opt`. +/// +/// The intention is to reduce the size of bloated wasm binaries as a result of missing +/// optimizations (or bugs?) between Rust and wasm. +/// +/// This step depends on the `wasm-opt` tool being installed. If it is not the build will still +/// succeed, and the user will be encouraged to install it for further optimizations. +fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { + // check `wasm-opt` installed + if which::which("wasm-opt").is_err() { + println!(" wasm-opt is not installed TODO: explain benefits - link to installation"); + return Ok(()) + } + + let mut optimized = crate_metadata.dest_wasm.clone(); + optimized.set_file_name(format!("{}-opt.wasm", crate_metadata.package_name)); + + let output = Command::new("wasm-opt") + .arg(crate_metadata.dest_wasm.as_os_str()) + .arg("-O3") // execute -O3 optimization passes (spends potentially a lot of time optimizing) + .arg("-o") + .arg(optimized.as_os_str()) + .output()?; + + if !output.status.success() { + // Dump the output streams produced by cargo into the stdout/stderr. + io::stdout().write_all(&output.stdout)?; + io::stderr().write_all(&output.stderr)?; + anyhow::bail!("wasm-opt optimization failed"); + } + + // overwrite existing destination wasm file with the optimised version + std::fs::rename(&optimized, &crate_metadata.dest_wasm)?; + Ok(()) +} + /// Executes build of the smart-contract which produces a wasm binary that is ready for deploying. /// /// It does so by invoking build by cargo and then post processing the final binary. pub(crate) fn execute_build(working_dir: Option<&PathBuf>) -> Result { - println!(" [1/3] Collecting crate metadata"); + println!(" [1/4] Collecting crate metadata"); let crate_metadata = collect_crate_metadata(working_dir)?; - println!(" [2/3] Building cargo project"); + println!(" [2/4] Building cargo project"); build_cargo_project(working_dir)?; - println!(" [3/3] Post processing wasm file"); + println!(" [3/4] Post processing wasm file"); post_process_wasm(&crate_metadata)?; + println!(" [4/4] Optimizing wasm file"); + optimize_wasm(&crate_metadata)?; Ok(format!( "Your contract is ready.\nYou can find it here:\n{}", -- GitLab From c130fc94a890af9595509cb40ab5704039dcc36d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Feb 2020 10:44:27 +0000 Subject: [PATCH 2/6] Friendly message and pretty colours --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 1 + src/cmd/build.rs | 21 ++++++++++++--------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 875f2235..49d4321a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,6 +269,7 @@ dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "async-std 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -347,6 +348,16 @@ dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "colored" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "const-random" version = "0.1.8" @@ -3084,6 +3095,7 @@ dependencies = [ "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" +"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" "checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" "checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" diff --git a/Cargo.toml b/Cargo.toml index 88a6be71..b858e4be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ parity-wasm = "0.41" cargo_metadata = "0.9" codec = { package = "parity-scale-codec", version = "1.1" } which = "3.1.0" +colored = "1.9" # dependencies for optional extrinsics feature async-std = { version = "1.2.0", optional = true } diff --git a/src/cmd/build.rs b/src/cmd/build.rs index d527b999..28e0c02a 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -23,6 +23,7 @@ use std::{ use anyhow::{Context, Result}; use cargo_metadata::MetadataCommand; use parity_wasm::elements::{External, MemoryType, Module, Section}; +use colored::Colorize; /// This is the maximum number of pages available for a contract to allocate. const MAX_MEMORY_PAGES: u32 = 16; @@ -168,8 +169,10 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> { /// succeed, and the user will be encouraged to install it for further optimizations. fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { // check `wasm-opt` installed - if which::which("wasm-opt").is_err() { - println!(" wasm-opt is not installed TODO: explain benefits - link to installation"); + if which::which("bwasm-opt").is_err() { + println!("{}", "wasm-opt is not installed. Install this tool on your system in order to \n\ + reduce the size of your contract's wasm binary. \n\ + See https://github.com/WebAssembly/binaryen#tools".bright_yellow()); return Ok(()) } @@ -184,7 +187,7 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { .output()?; if !output.status.success() { - // Dump the output streams produced by cargo into the stdout/stderr. + // Dump the output streams produced by wasm-opt into the stdout/stderr. io::stdout().write_all(&output.stdout)?; io::stderr().write_all(&output.stderr)?; anyhow::bail!("wasm-opt optimization failed"); @@ -199,18 +202,18 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { /// /// It does so by invoking build by cargo and then post processing the final binary. pub(crate) fn execute_build(working_dir: Option<&PathBuf>) -> Result { - println!(" [1/4] Collecting crate metadata"); + println!(" {} {}", "[1/4]".bold(), "Collecting crate metadata".bright_green().bold()); let crate_metadata = collect_crate_metadata(working_dir)?; - println!(" [2/4] Building cargo project"); + println!(" {} {}", "[2/4]".bold(), "Building cargo project".bright_green().bold()); build_cargo_project(working_dir)?; - println!(" [3/4] Post processing wasm file"); + println!(" {} {}", "[3/4]".bold(), "Post processing wasm file".bright_green().bold()); post_process_wasm(&crate_metadata)?; - println!(" [4/4] Optimizing wasm file"); + println!(" {} {}", "[4/4]".bold(), "Optimizing wasm file".bright_green().bold()); optimize_wasm(&crate_metadata)?; Ok(format!( - "Your contract is ready.\nYou can find it here:\n{}", - crate_metadata.dest_wasm.display() + "\nYour contract is ready. You can find it here:\n{}", + crate_metadata.dest_wasm.display().to_string().bold() )) } -- GitLab From 016562ea18dbc41a6c9c62c234555e6343a84413 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Feb 2020 10:59:54 +0000 Subject: [PATCH 3/6] Print optimized size compared to original --- src/cmd/build.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 28e0c02a..e0810083 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -16,6 +16,7 @@ use std::{ io::{self, Write}, + fs::metadata, path::PathBuf, process::Command, }; @@ -169,7 +170,7 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> { /// succeed, and the user will be encouraged to install it for further optimizations. fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { // check `wasm-opt` installed - if which::which("bwasm-opt").is_err() { + if which::which("wasm-opt").is_err() { println!("{}", "wasm-opt is not installed. Install this tool on your system in order to \n\ reduce the size of your contract's wasm binary. \n\ See https://github.com/WebAssembly/binaryen#tools".bright_yellow()); @@ -193,6 +194,10 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { anyhow::bail!("wasm-opt optimization failed"); } + let original_size = metadata(&crate_metadata.dest_wasm)?.len() / 1000; + let optimized_size = metadata(&optimized)?.len() / 1000; + println!(" Original wasm size: {}K, Optimized: {}K", original_size, optimized_size); + // overwrite existing destination wasm file with the optimised version std::fs::rename(&optimized, &crate_metadata.dest_wasm)?; Ok(()) -- GitLab From 351bf8e546176d5e4a0e8ef61a1b95e81abc2557 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Feb 2020 11:07:22 +0000 Subject: [PATCH 4/6] Fmt --- src/cmd/build.rs | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index e0810083..bca53438 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -15,16 +15,16 @@ // along with ink!. If not, see . use std::{ - io::{self, Write}, fs::metadata, + io::{self, Write}, path::PathBuf, process::Command, }; use anyhow::{Context, Result}; use cargo_metadata::MetadataCommand; -use parity_wasm::elements::{External, MemoryType, Module, Section}; use colored::Colorize; +use parity_wasm::elements::{External, MemoryType, Module, Section}; /// This is the maximum number of pages available for a contract to allocate. const MAX_MEMORY_PAGES: u32 = 16; @@ -171,10 +171,14 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> { fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { // check `wasm-opt` installed if which::which("wasm-opt").is_err() { - println!("{}", "wasm-opt is not installed. Install this tool on your system in order to \n\ - reduce the size of your contract's wasm binary. \n\ - See https://github.com/WebAssembly/binaryen#tools".bright_yellow()); - return Ok(()) + println!( + "{}", + "wasm-opt is not installed. Install this tool on your system in order to \n\ + reduce the size of your contract's wasm binary. \n\ + See https://github.com/WebAssembly/binaryen#tools" + .bright_yellow() + ); + return Ok(()); } let mut optimized = crate_metadata.dest_wasm.clone(); @@ -196,7 +200,10 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { let original_size = metadata(&crate_metadata.dest_wasm)?.len() / 1000; let optimized_size = metadata(&optimized)?.len() / 1000; - println!(" Original wasm size: {}K, Optimized: {}K", original_size, optimized_size); + println!( + " Original wasm size: {}K, Optimized: {}K", + original_size, optimized_size + ); // overwrite existing destination wasm file with the optimised version std::fs::rename(&optimized, &crate_metadata.dest_wasm)?; @@ -207,13 +214,29 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { /// /// It does so by invoking build by cargo and then post processing the final binary. pub(crate) fn execute_build(working_dir: Option<&PathBuf>) -> Result { - println!(" {} {}", "[1/4]".bold(), "Collecting crate metadata".bright_green().bold()); + println!( + " {} {}", + "[1/4]".bold(), + "Collecting crate metadata".bright_green().bold() + ); let crate_metadata = collect_crate_metadata(working_dir)?; - println!(" {} {}", "[2/4]".bold(), "Building cargo project".bright_green().bold()); + println!( + " {} {}", + "[2/4]".bold(), + "Building cargo project".bright_green().bold() + ); build_cargo_project(working_dir)?; - println!(" {} {}", "[3/4]".bold(), "Post processing wasm file".bright_green().bold()); + println!( + " {} {}", + "[3/4]".bold(), + "Post processing wasm file".bright_green().bold() + ); post_process_wasm(&crate_metadata)?; - println!(" {} {}", "[4/4]".bold(), "Optimizing wasm file".bright_green().bold()); + println!( + " {} {}", + "[4/4]".bold(), + "Optimizing wasm file".bright_green().bold() + ); optimize_wasm(&crate_metadata)?; Ok(format!( -- GitLab From f7e8f213a9c702fcde7fffc9c808c29a642274ea Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Feb 2020 13:27:19 +0000 Subject: [PATCH 5/6] Update src/cmd/build.rs Co-Authored-By: Hero Bird --- src/cmd/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index bca53438..da0b07c4 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -164,7 +164,7 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> { /// Attempts to perform optional wasm optimization using `wasm-opt`. /// /// The intention is to reduce the size of bloated wasm binaries as a result of missing -/// optimizations (or bugs?) between Rust and wasm. +/// optimizations (or bugs?) between Rust and Wasm. /// /// This step depends on the `wasm-opt` tool being installed. If it is not the build will still /// succeed, and the user will be encouraged to install it for further optimizations. -- GitLab From d8ffaaabb0a9a8296e3590164dfeff65d93e5584 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Feb 2020 13:27:26 +0000 Subject: [PATCH 6/6] Update src/cmd/build.rs Co-Authored-By: Hero Bird --- src/cmd/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index da0b07c4..c054f591 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -174,7 +174,7 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { println!( "{}", "wasm-opt is not installed. Install this tool on your system in order to \n\ - reduce the size of your contract's wasm binary. \n\ + reduce the size of your contract's Wasm binary. \n\ See https://github.com/WebAssembly/binaryen#tools" .bright_yellow() ); -- GitLab