Unverified Commit afc190bd authored by trace-andreason's avatar trace-andreason Committed by GitHub

Adding "optimization-passes" option (#216)

* ink::test attributes in new template

* add use ink

* adding optimization-passes option

* undoing unnecessary variable name change

* remove fork changes

* adding optimization_passes to tests

* cargo fmting

* switching to enum type

* Update src/main.rs
Co-authored-by: Michael Müller's avatarMichael Müller <mich@elmueller.net>

* Update src/main.rs
Co-authored-by: Michael Müller's avatarMichael Müller <mich@elmueller.net>

* Update src/main.rs
Co-authored-by: Michael Müller's avatarMichael Müller <mich@elmueller.net>

* Update src/main.rs
Co-authored-by: Michael Müller's avatarMichael Müller <mich@elmueller.net>

* Update src/main.rs
Co-authored-by: Michael Müller's avatarMichael Müller <mich@elmueller.net>

* adding cli help comment

* add line so default option is more visible

* Update src/cmd/build.rs
Co-authored-by: Michael Müller's avatarMichael Müller <mich@elmueller.net>
parent 4111385f
Pipeline #129298 failed with stages
in 3 minutes and 1 second
......@@ -29,8 +29,8 @@ use crate::{
crate_metadata::CrateMetadata,
maybe_println, util, validate_wasm,
workspace::{ManifestPath, Profile, Workspace},
BuildArtifacts, BuildResult, OptimizationResult, UnstableFlags, UnstableOptions, Verbosity,
VerbosityFlags,
BuildArtifacts, BuildResult, OptimizationFlags, OptimizationPasses, OptimizationResult,
UnstableFlags, UnstableOptions, Verbosity, VerbosityFlags,
};
use anyhow::{Context, Result};
use colored::Colorize;
......@@ -66,6 +66,8 @@ pub struct BuildCommand {
verbosity: VerbosityFlags,
#[structopt(flatten)]
unstable_options: UnstableOptions,
#[structopt(flatten)]
optimization_passes: OptimizationFlags,
}
impl BuildCommand {
......@@ -74,12 +76,15 @@ impl BuildCommand {
let unstable_flags: UnstableFlags =
TryFrom::<&UnstableOptions>::try_from(&self.unstable_options)?;
let verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;
let optimization_passes =
TryFrom::<&OptimizationFlags>::try_from(&self.optimization_passes)?;
execute(
&manifest_path,
verbosity,
true,
self.build_artifact,
unstable_flags,
optimization_passes,
)
}
}
......@@ -102,12 +107,14 @@ impl CheckCommand {
let unstable_flags: UnstableFlags =
TryFrom::<&UnstableOptions>::try_from(&self.unstable_options)?;
let verbosity: Verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;
let optimization_passes = OptimizationPasses::Zero;
execute(
&manifest_path,
verbosity,
false,
BuildArtifacts::CheckOnly,
unstable_flags,
optimization_passes,
)
}
}
......@@ -268,14 +275,16 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> {
///
/// The intention is to reduce the size of bloated wasm binaries as a result of missing
/// optimizations (or bugs?) between Rust and Wasm.
fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<OptimizationResult> {
fn optimize_wasm(
crate_metadata: &CrateMetadata,
optimization_passes: OptimizationPasses,
) -> Result<OptimizationResult> {
let mut dest_optimized = crate_metadata.dest_wasm.clone();
dest_optimized.set_file_name(format!("{}-opt.wasm", crate_metadata.package_name));
let _ = do_optimization(
crate_metadata.dest_wasm.as_os_str(),
&dest_optimized.as_os_str(),
3,
optimization_passes,
)?;
let original_size = metadata(&crate_metadata.dest_wasm)?.len() as f64 / 1000.0;
......@@ -299,17 +308,17 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<OptimizationResult> {
fn do_optimization(
dest_wasm: &OsStr,
dest_optimized: &OsStr,
optimization_level: u32,
optimization_level: OptimizationPasses,
) -> Result<()> {
let mut dest_wasm_file = File::open(dest_wasm)?;
let mut dest_wasm_file_content = Vec::new();
dest_wasm_file.read_to_end(&mut dest_wasm_file_content)?;
let codegen_config = binaryen::CodegenConfig {
// number of optimization passes (spends potentially a lot of time optimizing)
optimization_level,
// Number of optimization passes (spends potentially a lot of time optimizing)
optimization_level: optimization_level.to_passes(),
// the default
shrink_level: 1,
shrink_level: optimization_level.to_shrink(),
// the default
debug_info: false,
};
......@@ -334,7 +343,7 @@ fn do_optimization(
fn do_optimization(
dest_wasm: &OsStr,
dest_optimized: &OsStr,
optimization_level: u32,
optimization_level: OptimizationPasses,
) -> Result<()> {
// check `wasm-opt` is installed
if which::which("wasm-opt").is_err() {
......@@ -349,7 +358,7 @@ fn do_optimization(
let output = Command::new("wasm-opt")
.arg(dest_wasm)
.arg(format!("-O{}", optimization_level))
.arg(format!("-O{}", optimization_level.to_str()))
.arg("-o")
.arg(dest_optimized)
// the memory in our module is imported, `wasm-opt` needs to be told that
......@@ -381,6 +390,7 @@ fn execute(
optimize_contract: bool,
build_artifact: BuildArtifacts,
unstable_flags: UnstableFlags,
optimization_passes: OptimizationPasses,
) -> Result<BuildResult> {
if build_artifact == BuildArtifacts::CodeOnly || build_artifact == BuildArtifacts::CheckOnly {
let crate_metadata = CrateMetadata::collect(manifest_path)?;
......@@ -390,6 +400,7 @@ fn execute(
optimize_contract,
build_artifact,
unstable_flags,
optimization_passes,
)?;
let res = BuildResult {
dest_wasm: maybe_dest_wasm,
......@@ -403,7 +414,13 @@ fn execute(
return Ok(res);
}
let res = super::metadata::execute(&manifest_path, verbosity, build_artifact, unstable_flags)?;
let res = super::metadata::execute(
&manifest_path,
verbosity,
build_artifact,
unstable_flags,
optimization_passes,
)?;
Ok(res)
}
......@@ -422,6 +439,7 @@ pub(crate) fn execute_with_crate_metadata(
optimize_contract: bool,
build_artifact: BuildArtifacts,
unstable_flags: UnstableFlags,
optimization_passes: OptimizationPasses,
) -> Result<(Option<PathBuf>, Option<OptimizationResult>)> {
maybe_println!(
verbosity,
......@@ -449,7 +467,7 @@ pub(crate) fn execute_with_crate_metadata(
format!("[3/{}]", build_artifact.steps()).bold(),
"Optimizing wasm file".bright_green().bold()
);
let optimization_result = optimize_wasm(&crate_metadata)?;
let optimization_result = optimize_wasm(&crate_metadata, optimization_passes)?;
Ok((
Some(crate_metadata.dest_wasm.clone()),
Some(optimization_result),
......@@ -469,12 +487,14 @@ mod tests_ci_only {
cmd::new::execute("new_project", Some(path)).expect("new project creation failed");
let manifest_path =
ManifestPath::new(&path.join("new_project").join("Cargo.toml")).unwrap();
let optimization_passes = 3;
let res = super::execute(
&manifest_path,
Verbosity::Default,
true,
BuildArtifacts::All,
UnstableFlags::default(),
optimization_passes,
)
.expect("build failed");
......@@ -503,6 +523,7 @@ mod tests_ci_only {
cmd::new::execute("new_project", Some(path)).expect("new project creation failed");
let project_dir = path.join("new_project");
let manifest_path = ManifestPath::new(&project_dir.join("Cargo.toml")).unwrap();
let optimization_passes = 3;
// when
super::execute(
......@@ -511,6 +532,7 @@ mod tests_ci_only {
true,
BuildArtifacts::CheckOnly,
UnstableFlags::default(),
optimization_passes,
)
.expect("build failed");
......
......@@ -18,7 +18,7 @@ use crate::{
crate_metadata::CrateMetadata,
maybe_println, util,
workspace::{ManifestPath, Workspace},
BuildArtifacts, BuildResult, OptimizationResult, UnstableFlags, Verbosity,
BuildArtifacts, BuildResult, OptimizationPasses, OptimizationResult, UnstableFlags, Verbosity,
};
use anyhow::Result;
......@@ -40,6 +40,7 @@ struct GenerateMetadataCommand {
verbosity: Verbosity,
build_artifact: BuildArtifacts,
unstable_options: UnstableFlags,
optimization_passes: OptimizationPasses,
}
/// Result of generating the extended contract project metadata
......@@ -239,6 +240,7 @@ impl GenerateMetadataCommand {
true, // for the hash we always use the optimized version of the contract
self.build_artifact,
self.unstable_options.clone(),
self.optimization_passes,
)?;
let wasm = fs::read(&self.crate_metadata.dest_wasm)?;
......@@ -265,6 +267,7 @@ pub(crate) fn execute(
verbosity: Verbosity,
build_artifact: BuildArtifacts,
unstable_options: UnstableFlags,
optimization_passes: OptimizationPasses,
) -> Result<BuildResult> {
let crate_metadata = CrateMetadata::collect(manifest_path)?;
let res = GenerateMetadataCommand {
......@@ -272,6 +275,7 @@ pub(crate) fn execute(
verbosity,
build_artifact,
unstable_options,
optimization_passes,
}
.exec()?;
Ok(res)
......
......@@ -93,6 +93,100 @@ impl ExtrinsicOpts {
}
}
#[derive(Clone, Debug, StructOpt)]
pub struct OptimizationFlags {
/// number of optimization passes, passed as an argument to wasm-opt
///
/// - `0`: execute no optimization passes
///
/// - `1`: execute 1 optimization pass (quick & useful opts, useful for iteration builds)
///
/// - `2`, execute 2 optimization passes (most opts, generally gets most perf)
///
/// - `3`, execute 3 optimization passes (spends potentially a lot of time optimizing)
///
/// - `4`, execute 4 optimization passes (also flatten the IR, which can take a lot more time and memory
/// but is useful on more nested / complex / less-optimized input)
///
/// - `s`, execute default optimization passes, focusing on code size
///
/// - `z`, execute default optimization passes, super-focusing on code size
///
/// -
#[structopt(long = "optimization-passes", default_value = "3")]
optimization_passes: String,
}
#[derive(Clone, Copy)]
pub enum OptimizationPasses {
Zero,
One,
Two,
Three,
Four,
S,
Z,
}
impl TryFrom<&OptimizationFlags> for OptimizationPasses {
type Error = Error;
fn try_from(value: &OptimizationFlags) -> Result<Self, Self::Error> {
match value.optimization_passes.to_lowercase().as_str() {
"0" => Ok(OptimizationPasses::Zero),
"1" => Ok(OptimizationPasses::One),
"2" => Ok(OptimizationPasses::Two),
"3" => Ok(OptimizationPasses::Three),
"4" => Ok(OptimizationPasses::Four),
"s" => Ok(OptimizationPasses::S),
"z" => Ok(OptimizationPasses::Z),
_ => anyhow::bail!(
"Unknown optimization passes option {}",
value.optimization_passes
),
}
}
}
impl OptimizationPasses {
/// Returns the string representation of `OptimizationPasses`
pub(crate) fn to_str(&self) -> &str {
match self {
OptimizationPasses::Zero => "0",
OptimizationPasses::One => "1",
OptimizationPasses::Two => "2",
OptimizationPasses::Three => "3",
OptimizationPasses::Four => "4",
OptimizationPasses::S => "s",
OptimizationPasses::Z => "z",
}
}
/// Returns the number of optimization passes to do
#[cfg(feature = "binaryen-as-dependency")]
pub(crate) fn to_passes(&self) -> u32 {
match self {
OptimizationPasses::Zero => 0,
OptimizationPasses::One => 1,
OptimizationPasses::Two => 2,
OptimizationPasses::Three => 3,
OptimizationPasses::Four => 4,
_ => 3, // Default to three for shrink settings
}
}
/// Returns amount of shrinkage to do
#[cfg(feature = "binaryen-as-dependency")]
pub(crate) fn to_shrink(&self) -> u32 {
match self {
OptimizationPasses::Zero => 0,
OptimizationPasses::S => 1,
OptimizationPasses::Z => 2,
_ => 1,
}
}
}
#[derive(Clone, Debug, StructOpt)]
pub struct VerbosityFlags {
/// No output printed to stdout
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment