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

feat(std/hash): reimplement all hashes in WASM #6292

Merged
merged 1 commit into from
Jun 16, 2020

Conversation

skdltmxn
Copy link
Contributor

This PR is renewal of #6046.
WASM implementation is at https://github.com/skdltmxn/deno-hash

@skdltmxn
Copy link
Contributor Author

Benchmark shows that WASM version is slower than native Rust but is faster than JS version.

10mb

Algorithm JS Rust WASM
md5 227 75 125
sha1 256 76 162
sha224 400 105 202
sha256 392 101 203
sha512 339 84 174
sha3-224 273 88 197
sha3-256 282 91 201
sha3-384 328 101 239
sha3-512 418 118 281

100mb

Algorithm JS Rust WASM
md5 1751 299 501
sha1 1961 309 904
sha224 3368 555 1301
sha256 3338 553 1298
sha512 2697 382 1026
sha3-224 1938 439 1275
sha3-256 2009 453 1338
sha3-384 2480 546 1546
sha3-512 3324 721 2250

@kitsonk
Copy link
Contributor

kitsonk commented Jun 15, 2020

I haven't dug into the PR in depth, but this is awesome! Not adding to the Deno binary, but providing hot path performance improvement. It also proves that WebAssembly doesn't perform better than Rust, so it isn't suitable for all hot paths, but it feels suitable for this one, as it is something that isn't part of the core of Deno, so it is a good mediation between all the options.

@caspervonb
Copy link
Contributor

caspervonb commented Jun 15, 2020

Generally speaking, pure computation that doesn't trampoline between JS/WASM in a hot path should be very close native code once v8 has warmed up so these measurements look a little off at first glance.

Based on the previous pull request, assuming these benchmarks are done the same way; the benchmarks seem to be including startup time?

def run_benchmark(deno_exe, method, input_file):
     # compile
     subprocess.call([deno_exe, "run", "cli/tests/hash/hash.ts"])

     for alg in algorithms:
         args = [
             deno_exe, "run", "--allow-read", "cli/tests/hash/hash.ts", method,
             alg, input_file
         ]

         start = time.time()
         subprocess.call(args)
         elapsed = time.time() - start

         print "[{}] {}ms".format(alg, int(elapsed * 1000))

It would be more accurate if the measurement did not include the time it takes for a WebAssembly module to be decoded from base64, compiled to a module and instantiated as an instance.

@skdltmxn
Copy link
Contributor Author

@caspervonb Thank you for the tips! New benchmark for pure computation actually shows that WASM version is pretty fast!

10mb

Algorithm JS Rust WASM
md5 199 75 35
sha1 196 76 75
sha224 352 105 116
sha256 328 101 115
sha512 281 84 88
sha3-224 213 88 110
sha3-256 223 91 115
sha3-384 274 101 150
sha3-512 352 118 191

100mb

Algorithm JS Rust WASM
md5 1539 299 329
sha1 1819 309 721
sha224 3180 555 1120
sha256 3127 553 1151
sha512 2584 382 855
sha3-224 1794 439 1038
sha3-256 1884 453 1089
sha3-384 2337 546 1384
sha3-512 3188 721 1930

Copy link
Member

@ry ry left a comment

Choose a reason for hiding this comment

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

@skdltmxn I agree with Kitson, this is awesome! Thanks for this work.

I would like to have the source code of how the wasm is generated in the tree - even tho we check-in the output. This will allow us to update and maintain it without depending on your repository. So could you please copy the files in https://github.com/skdltmxn/deno-hash over into std/hash/_wasm ?

@skdltmxn
Copy link
Contributor Author

@ry Sure. That's a good idea. Would it be okay to copy whole repo into std/hash/_wasm?

@ry
Copy link
Member

ry commented Jun 15, 2020

@skdltmxn Yes, ideally removing as many files as possible and with a readme that gives the explicit commands to run in order to regenerate the wasm file

#hash: DenoHash;
#digested: boolean;

constructor(algorithm: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be changed to: algorithm: SupportedAlgorithm instead of algorithm: string?

And you can remove as string

deno/std/hash/mod.ts

Lines 32 to 34 in b59bab3

export function createHash(algorithm: SupportedAlgorithm): Hasher {
return new Hash(algorithm as string);
}

Copy link
Contributor Author

@skdltmxn skdltmxn Jun 15, 2020

Choose a reason for hiding this comment

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

In order to use SupportedAlgorithm in hash.ts, I have to import mod.ts.
But mod.ts is also importing hash.ts, so I thought it would make cycle.

Copy link
Contributor Author

@skdltmxn skdltmxn Jun 15, 2020

Choose a reason for hiding this comment

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

In architectural point of view, I think Hash class doesn't need to know about SupportedAlgorithm since Hash is just an wrapper for WASM which only uses string.
SupportedAlgorithm would do enough of its job for guarding algorithm for createHash defined in mod.ts.

@skdltmxn
Copy link
Contributor Author

@ry I have copied deno-hash repo into std/hash/_wasm. Please check README for build!

Cargo.toml Show resolved Hide resolved
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.

import { encode as base64Encode } from "../../encoding/base64.ts";
import Terser from "https://cdn.pika.dev/terser@^4.7.0";
Copy link
Member

Choose a reason for hiding this comment

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

What does terser do?

Copy link
Member

Choose a reason for hiding this comment

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

I see - it's a minifier. Is it possible to remove this dependency? Presumably minification doesn't help much?

In std we strive to not have any external dependencies: https://deno.land/manual/contributing/style_guide#minimize-dependencies-do-not-make-circular-imports
In this case, build.ts isn't part of std, it's just a script for generating the wasm, but I think it would be prudent for us to not rely on external code if possible.

Copy link
Member

Choose a reason for hiding this comment

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

Also I'm getting an error when running this:

> deno run --allow-read --allow-write --allow-run ./build.ts
Download https://cdn.pika.dev/terser@^4.7.0
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019/terser.js
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/tools/terser.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019/source-map.js
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/tools/terser.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/source-map.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Compile file:https:///Users/rld/src/deno/std/hash/_wasm/build.ts
error: Uncaught SyntaxError: Invalid or unexpected token
    at https://cdn.pika.dev/-/[email protected]/dist=es2019/terser.js:10:342617

Copy link
Contributor

Choose a reason for hiding this comment

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

It should make a huge difference if we are targeting wasm. Mostly it would be shortening variable names, the rest simply shouldn't matter in Web Assembly.

Adding minification support into Deno longer term is an objective, but we would want that to come from Rust.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will remove minifier :)

@skdltmxn skdltmxn force-pushed the std-hash-wasm branch 2 times, most recently from 5975b66 to 784896b Compare June 16, 2020 12:51
@skdltmxn
Copy link
Contributor Author

@ry Removed Terser from WASM build script.

I'm still not sure whether it is better to include WASM project into root Cargo.toml or not since we don't have to build WASM everytime and building WASM is done using deno itself.

@ry
Copy link
Member

ry commented Jun 16, 2020

@skdltmxn I'm not sure either. Let's exclude it for now. We'll have to develop our own best practices for managing wasm in std - thanks for blazing a path : )

@ry
Copy link
Member

ry commented Jun 16, 2020

So I ran the build.ts script, and it was successful, but it creates an out directory:

> ls out
README.md         deno_hash.js      deno_hash_bg.wasm
deno_hash.d.ts    deno_hash_bg.d.ts package.json

It seems there's probably a final step:

cp out/deno_hash.js ./wasm.js

Is this correct? If so, can you please update the readme?

@ry
Copy link
Member

ry commented Jun 16, 2020

Oops, nope. It seems the build.ts does that. Sorry.

However, I noticed in build.ts it uses an absolute URL: https://deno.land/[email protected]/encoding/base64.ts

can you change this to be a relative URL?

@skdltmxn
Copy link
Contributor Author

@ry All fixed!

Copy link
Member

@ry ry left a comment

Choose a reason for hiding this comment

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

LGTM - thanks @skdltmxn !

I think we might have to continue iterating on this for a bit - but this is good enough for now

@ry ry merged commit b3c72d1 into denoland:master Jun 16, 2020
@skdltmxn skdltmxn deleted the std-hash-wasm branch June 17, 2020 01:00
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 21, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 24, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 24, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 24, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants