Skip to content

Optimize atob/btoa by using base64-simd #14980

@Nugine

Description

@Nugine

I replace the base64 crate with base64-simd in ext/web/lib.rs and test whether it has better performance.

fn b64_encode(s: &[u8]) -> String {
  base64_simd::Base64::STANDARD.encode_to_boxed_str(s).into()
}

fn b64_decode(mut buf: Vec<u8>) -> Result<Vec<u8>, AnyError> {
  let on_err =
    || DomExceptionInvalidCharacterError::new("Failed to decode base64");

  let decoded_length = base64_simd::Base64::STANDARD
    .decode_inplace(&mut buf)
    .map_err(|_| on_err())?
    .len();

  buf.truncate(decoded_length);
  Ok(buf)
}

Here is the result:

node v18.4.0
b64Long:        n = 100,                dt = 11.080s,   freq = 9.025/s,         time = 110.802ms/op
b64Short:       n = 1000000,            dt = 1.170s,    freq = 854599.570/s,    time = 1170ns/op
deno 1.23.1
b64Long:        n = 100,                dt = 0.534s,    freq = 187.266/s,       time = 5.340ms/op
b64Short:       n = 1000000,            dt = 0.652s,    freq = 1533742.331/s,   time = 652ns/op
deno (base64-simd v0.6.0-dev)
b64Long:        n = 100,                dt = 0.290s,    freq = 344.828/s,       time = 2.900ms/op
b64Short:       n = 1000000,            dt = 0.520s,    freq = 1923076.923/s,   time = 520ns/op
bench function
// Extracted from <https://github.com/denoland/deno/blob/main/cli/bench/deno_common.js>

function bench(name, n, f) {
    const t1 = performance.now();
    for (let i = 0; i < n; ++i) {
        f(i);
    }
    const t2 = performance.now();

    const dt = (t2 - t1) / 1e3;
    const freq = n / dt;
    const time = (t2 - t1) / n;

    const msg = [
        `${name}:     \t`,
        `n = ${n},          \t`,
        `dt = ${dt.toFixed(3)}s, \t`,
        `freq = ${freq.toFixed(3)}/s, \t`,
    ]

    if (time >= 1) {
        msg.push(`time = ${time.toFixed(3)}ms/op`)
    } else {
        msg.push(`time = ${(time * 1e6).toFixed(0)}ns/op`)
    }

    console.log(msg.join(""))
}

function b64Long() {
    const input = "helloworld".repeat(1e5);
    bench("b64Long", 100, () => {
        atob(btoa(input));
    });
}

function b64Short() {
    const input = "123";
    bench("b64Short", 1e6, () => {
        atob(btoa(input));
    });
}

b64Long();
b64Short();

Metadata

Metadata

Assignees

No one assigned

    Labels

    ext/webrelated to the ext/web crateperfperformance related

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions