Stream: git-wasmtime

Topic: wasmtime / issue #11076 Wasm component get slower with a ...


view this post on Zulip Wasmtime GitHub notifications bot (Jun 19 2025 at 12:49):

wynterr opened issue #11076:

Hi, I'm working on a project where I'm compiling Rust code into a Wasm component using cargo-component, and hosting that component using the Wasmtime Rust SDK.

My Wasm component depends on OpenSSL, so I first compiled OpenSSL to Wasm and then linked it into my project. However, my custom logic only uses a small portion of OpenSSL, yet the resulting .wasm file is significantly larger than necessary due to the full inclusion of the OpenSSL dependency.

I experimented with different pre-compiled Wasm versions of OpenSSL from GitHub, and observed the following:

To reduce file size and improve performance, I also tried compiling my project to a regular Wasm module (instead of a component), and ran wasm-opt to optimize it. This reduced the file size and improved execution speed as expected.

However, wasm-opt currently does not support Wasm components.

So my questions are:

  1. Why does increasing the size of the Wasm component (even if unrelated to the actual execution path) cause slower runtime performance, especially for specific function calls into OpenSSL?
  2. Are there any tools or workflows available to optimize or shrink Wasm components, similar to what wasm-opt does for modules?

Thanks!

view this post on Zulip Wasmtime GitHub notifications bot (Jun 20 2025 at 14:18):

alexcrichton commented on issue #11076:

Would you be able to share numbers/examples/wasms? It is not expected that the size of a component affects speed (in the same way the size of a core module should not affect speed). That may mean that you're running into a bug and/or something else, so specific numbers, examples, or wasm files will help to debug that.

As for shrinking a component, no there's no integration I'm aware of with wasm-opt at this time. It's theoretically possible to run wasm-opt individually over each module within a component, but that has not yet been implemented.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 20 2025 at 21:30):

primoly commented on issue #11076:

  1. Are there any tools or workflows available to optimize or shrink Wasm components, similar to what wasm-opt does for modules?

There’s component-opt. It scoops out all the modules inside the component, runs wasm-opt on them and reassembles the component with the optimised modules. But I believe it uses an old version of Binaryen: 116 from September 2023.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 24 2025 at 10:15):

wynterr commented on issue #11076:

Would you be able to share numbers/examples/wasms? It is not expected that the size of a component affects speed (in the same way the size of a core module should not affect speed). That may mean that you're running into a bug and/or something else, so specific numbers, examples, or wasm files will help to debug that.

As for shrinking a component, no there's no integration I'm aware of with wasm-opt at this time. It's theoretically possible to run wasm-opt individually over each module within a component, but that has not yet been implemented.

Thank you for the response.
Due to company policy I can't share the wasm files. So I tried to build a mininal example Rust project that does simply a signature verification by openssl and compiled it to a wasm module.

use openssl::ec::{EcGroup, EcKey};
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::sign::{Signer, Verifier};
use openssl::hash::MessageDigest;
use std::time::Instant;

#[no_mangle]
pub extern "C" fn test_openssl() -> bool {
    let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
    let key = EcKey::generate(&group).unwrap();
    let pkey = PKey::from_ec_key(key).unwrap();

    let data = b"test data";

    let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
    signer.update(data).unwrap();
    let signature = signer.sign_to_vec().unwrap();

    let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
    let mut total = std::time::Duration::new(0, 0);
    for _ in 0..100 {
        let start = Instant::now();
        verifier.update(data).unwrap();
        verifier.verify(&signature).unwrap();
        total += start.elapsed();
    }
    println!("avg {:?}", total / 100);
    true
}

And the result for this example:

  1. With self-built wasm openssl
  1. With self-built openssl + wasm-opt
  1. With https://github.com/jedisct1/openssl-wasm
  1. With https://github.com/wapm-packages/OpenSSL/tree/master
  1. Native binary:

All wasm files were tested using the following command:
wasmtime -W unknown-imports-default=y -S cli=y --dir . --invoke test_openssl test_openssl.wasm

For this example, using wasm-opt does reduce its size but actually doesn't improve the speed. Using pre-compiled openssl from github still improves the speed. So maybe it is not the size that matters. It could be wasm-opt that optimizes the performance(for my custom wasm file it does help to boost the performace from ~25ms to ~18ms), and different wasm builds of openssl yield different performance.

Another thing I’m curious about is why OpenSSL performs so poorly when compiled to WebAssembly, especially compared to other parts of my project, which don’t exhibit the same level of performance degradation. This might not be directly related to Wasmtime itself, but I’d really appreciate any insights into what might be causing this. Thanks!

view this post on Zulip Wasmtime GitHub notifications bot (Jun 24 2025 at 10:18):

wynterr commented on issue #11076:

  1. Are there any tools or workflows available to optimize or shrink Wasm components, similar to what wasm-opt does for modules?

There’s component-opt. It scoops out all the modules inside the component, runs wasm-opt on them and reassembles the component with the optimised modules. But I believe it uses an old version of Binaryen: 116 from September 2023.

Thanks for the info. I just tried it and getting some error saying type index 0 is not a resource type. Maybe it's because of the older version of Binaryen they use.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 24 2025 at 10:20):

bjorn3 commented on issue #11076:

Another thing I’m curious about is why OpenSSL performs so poorly when compiled to WebAssembly, especially compared to other parts of my project, which don’t exhibit the same level of performance degradation. This might not be directly related to Wasmtime itself, but I’d really appreciate any insights into what might be causing this. Thanks!

That could be OpenSSL having a SIMD implementation of this crypto primitive for x86_64, but missing one for wasm.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 24 2025 at 14:46):

alexcrichton commented on issue #11076:

It looks like you're using different builds of OpenSSL, so can you explain why you think they should all perform the same? They could all have different build flags, come from different sources, or have different patches which could explain the performance difference. This to me looks like it's unrelated to the size of a component and more related to the actual code in the component as to what's taking awhile here or not.

And yes, OpenSSL likely has far more vectorized/optimized routines for native than for wasm, so wasm is unlikely to be as fast as native.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 25 2025 at 06:34):

wynterr closed issue #11076:

Hi, I'm working on a project where I'm compiling Rust code into a Wasm component using cargo-component, and hosting that component using the Wasmtime Rust SDK.

My Wasm component depends on OpenSSL, so I first compiled OpenSSL to Wasm and then linked it into my project. However, my custom logic only uses a small portion of OpenSSL, yet the resulting .wasm file is significantly larger than necessary due to the full inclusion of the OpenSSL dependency.

I experimented with different pre-compiled Wasm versions of OpenSSL from GitHub, and observed the following:

To reduce file size and improve performance, I also tried compiling my project to a regular Wasm module (instead of a component), and ran wasm-opt to optimize it. This reduced the file size and improved execution speed as expected.

However, wasm-opt currently does not support Wasm components.

So my questions are:

  1. Why does increasing the size of the Wasm component (even if unrelated to the actual execution path) cause slower runtime performance, especially for specific function calls into OpenSSL?
  2. Are there any tools or workflows available to optimize or shrink Wasm components, similar to what wasm-opt does for modules?

Thanks!

view this post on Zulip Wasmtime GitHub notifications bot (Jun 25 2025 at 06:34):

wynterr commented on issue #11076:

It looks like you're using different builds of OpenSSL, so can you explain why you think they should all perform the same? They could all have different build flags, come from different sources, or have different patches which could explain the performance difference. This to me looks like it's unrelated to the size of a component and more related to the actual code in the component as to what's taking awhile here or not.

And yes, OpenSSL likely has far more vectorized/optimized routines for native than for wasm, so wasm is unlikely to be as fast as native.

Yeah, I realized this after running experiments with the minimal example. Thanks for the response.


Last updated: Dec 06 2025 at 06:05 UTC